使用Mina框架開發 QQ Android 客戶端

Apache MINA是一個網絡應用程序框架,用來幫助用戶簡單地開發高性能和高可靠性的網絡應用程序。它提供了一個經過Java NIO在不一樣的傳輸例如TCP/IP和UDP/IP上抽象的事件驅動的異步API。java

  Apache MINA 也稱爲:
  ● NIO 框架庫
  ● 客戶端服務器框架庫
  ● 一個網絡套接字庫
  MINA雖然簡單可是仍然提供了全功能的網絡應用程序框架:
  ● 爲不一樣的傳輸類型提供了統一的API:
  ○ 經過Java NIO提供TCP/IP 和 UDP/IP支持
  ○ 經過RXTX提供串口通信(RS232)
  ○ In-VM管道通信
  ○ 你能實現你本身的API!
  ● 過濾器做爲一個擴展特性; 相似Servlet過濾器
  ● 低級和高級的API:
  ○ 低級: 使用字節緩存(ByteBuffers)
  ○ 高級: 使用用戶定義的消息對象(objects)和編碼(codecs)
  ● 高度定製化線程模型:
  ○ 單線程
  ○ 一個線程池
  ○ 一個以上的線程池(也就是SEDA)
  ● 使用Java 5 SSL引擎提供沙盒(Out-of-the-box) SSL · TLS · StartTLS支持
  ● 超載保護和傳輸流量控制
  ● 利用模擬對象進行單元測試
  ● JMX管理能力
  ● 經過StreamIoHandler提供基於流的I/O支持
  ● 和知名的容器(例如PicoContainer、Spring)集成
  ● 從Netty平滑的遷移到MINA, Netty是MINA的前輩。linux

MINA 基本類的描述 : 
IoAccepter 至關於網絡應用程序中的服務器端 
IoConnector 至關於客戶端 
IoSession 當前客戶端到服務器端的一個鏈接實例 
IoHandler 業務處理邏輯 
IoFilter 過濾器用於懸接通信層接口與業務層接口數據庫

要編寫和運行一個基於Apache MINA 2.0的程序,須要JDK 5.0以上版本,api

下面看一個domo:緩存

準備工做:服務器

mina-core-2.0.0-M6.jar
slf4j-api-1.5.2.jar網絡


在官網下載到mina,找出這幾個jar,添加到項目,session

服務端的代碼:框架

  1. public class MainFrame { 
  2.     private static final int PORT=5469; 
  3.      
  4.     public static void main(String[] args) throws Exception{ 
  5.         IoAcceptor acceptor=new NioSocketAcceptor(); 
  6.         IoFilter filter=new ProtocolCodecFilter(new TextLineCodecFactory()); 
  7.         acceptor.getFilterChain().addLast("vestigge", filter); 
  8.         acceptor.setHandler(new ServerHandler()); 
  9.         acceptor.bind(new InetSocketAddress(PORT)); 
  10.          
  11.         System.out.println( "服務器正在監聽端口" + PORT +"..."); 
  12.     } 

其中new ServerHandler()傳入的是實現了IoHandler接口的類,代碼以下:dom

  1. public class ServerHandler extends IoHandlerAdapter { 
  2.  
  3.     @Override 
  4.     public void messageReceived(IoSession session, Object message) 
  5.             throws Exception { 
  6.         System.out.println("收到客戶端消息:" + message.toString()); 
  7.     } 
  8.      
  9.     @Override 
  10.     public void exceptionCaught(IoSession session, Throwable cause) 
  11.             throws Exception { 
  12.         System.out.println("服務器出現異常:" +cause); 
  13.     } 
  14.  

重寫了父類中的messageReceived()和exceptionCaught()

通常在messageReceived()中對客戶端的請求進行業務,邏輯處理

下面在命令行用telnet測試一下,

若是是win 7沒有telnet,找到「打開或關閉Windows功能」 ,找到telnet客戶端和telnet服務端,勾選便可,

在命令行下輸入telnet 127.0.0.1 5469

而後再telnet窗口中輸入幾個字符回車,在控制檯能夠看到服務器成功收到了消息:

 

上節中經過一個簡單的例子,對Mina框架有了大致的瞭解,在上節的基礎上,看看 怎樣實現客戶端與服務端的通訊,

廢話很少說了,直接看代碼:

  1. public class Test { 
  2.  
  3.     public static void main(String[] args) throws Exception{ 
  4.         SocketConnector connector = new NioSocketConnector(); 
  5.         IoFilter filter = new ProtocolCodecFilter(new TextLineCodecFactory()); 
  6.         connector.getFilterChain().addLast("vestigge", filter); 
  7.         SocketAddress soketAddress = new InetSocketAddress("127.0.0.1", 5469); 
  8.         connector.setHandler(new ClientHandler()); 
  9.         ConnectFuture future= connector.connect(soketAddress); 
  10.         future.join(); 
  11.         if (!future.isConnected()) { 
  12.             System.out.println("鏈接服務器失敗"); 
  13.             return
  14.         } 
  15.         future.getSession().write("hello"); 
  16.     } 

能夠看到代碼與服務器端的代碼很像,也是很是的簡單,這就是框架的好處,不用再重複發明輪子,省了很多事,

  1. public class ClientHandler extends IoHandlerAdapter { 
  2.      
  3.     public void messageReceived(IoSession arg0, Object message) throws Exception { 
  4.         System.out.println("收到服務器消息:" + message.toString()); 
  5.     } 
  6.  
  7.     public void exceptionCaught(IoSession arg0, Throwable arg1) 
  8.             throws Exception { 
  9.  
  10.     } 

效果演示:

 

登錄界面的文章 http://www.linuxidc.com/Linux/2012-11/73437.htm

就不在重複了,直接看登錄的代碼,

用Mina傳遞字符串上節已經看過了,要實現傳遞對象,也很是簡單,只須要修改一下過濾器:

chain.addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); 

Android客戶端,登錄的Activity中:

  1. public class LoginActivity extends Activity{ 
  2.     private EditText accountEditText; 
  3.     private EditText passwordEditText; 
  4.     private CheckBox remeberCheckBox; 
  5.      
  6.      public void onCreate(Bundle savedInstanceState) { 
  7.             super.onCreate(savedInstanceState); 
  8.             requestWindowFeature(Window.FEATURE_NO_TITLE); 
  9.             setContentView(R.layout.activity_login); 
  10.             accountEditText=(EditText) findViewById(R.id.login_account); 
  11.             passwordEditText=(EditText) findViewById(R.id.login_password); 
  12.             remeberCheckBox=(CheckBox) findViewById(R.id.login_remember); 
  13.              
  14.             findViewById(R.id.login_login).setOnClickListener(new OnClickListener(){ 
  15.                 public void onClick(View v) { 
  16.                     if(accountEditText.getText().toString().equals("") ||   
  17.                             passwordEditText.getText().toString().equals("")){ 
  18.                         Toast.makeText(LoginActivity.this"帳號或密碼不能爲空!", Toast.LENGTH_SHORT).show(); 
  19.                     }else
  20.                         User user=new User(); 
  21.                         user.setAccount(Integer.parseInt(accountEditText.getText().toString())); 
  22.                         user.setPassword(passwordEditText.getText().toString()); 
  23.                         user.setOperation(VQMessageType.LOGIN); 
  24.                         boolean b=new VQClient().sendLoginInfo(user); 
  25.                         //若是登陸成功  
  26.                         if(b){ 
  27.                             Toast.makeText(LoginActivity.this"登錄成功!", Toast.LENGTH_SHORT).show(); 
  28.                             startActivity(new Intent(LoginActivity.this,MainActivity.class)); 
  29.                         }else
  30.                             Toast.makeText(LoginActivity.this"鏈接超時,登錄失敗!", Toast.LENGTH_SHORT).show(); 
  31.                         } 
  32.                     } 
  33.                 } 
  34.             }); 
  35.      } 

能夠看到會調用VQClient這個類中的方法去發送登錄請求,VQClient的實現:

  1. public class VQClient { 
  2.     private static int PORT=5469; 
  3.     public boolean sendLoginInfo(User u){ 
  4.         boolean b=false
  5.         System.setProperty("java.net.preferIPv6Addresses", "false");//2.2會有ipv6的問題,  
  6.         SocketConnector connector = new NioSocketConnector(); 
  7.         connector.setConnectTimeoutMillis(300000); 
  8.         DefaultIoFilterChainBuilder chain=connector.getFilterChain(); 
  9.         chain.addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); 
  10.         SocketSessionConfig cfg = connector.getSessionConfig(); 
  11.         cfg.setUseReadOperation(true);   
  12.         IoSession session = connector.connect(new InetSocketAddress("10.0.2.2", PORT))   
  13.                 .awaitUninterruptibly().getSession(); 
  14.         //發送並等待完成  
  15.         session.write(u).awaitUninterruptibly(); 
  16.         //接收  
  17.         ReadFuture readFuture = session.read(); 
  18.         //接收超時  
  19.         if (readFuture.awaitUninterruptibly(30000,TimeUnit.SECONDS)) {   
  20.             VQMessage message = (VQMessage) readFuture.getMessage(); 
  21.             //若是是登錄成功的信息  
  22.             if(message.getType().equals(VQMessageType.SUCCESS)){ 
  23.                 b= true
  24.             } 
  25.         } else { 
  26.             b= false
  27.         }   
  28.         //斷開鏈接  
  29.         session.close(true);   
  30.         session.getService().dispose();   
  31.         return b; 
  32.     } 

而後服務器端變化不大,在收到登錄請求後,會查詢數據庫,返回一個信息,來代表登錄成功或者失敗。

  1. public void messageReceived(IoSession session, Object message) 
  2.             throws Exception { 
  3.         User user=(User) message; 
  4.         if(user.getOperation().equals(VQMessageType.LOGIN)){ 
  5.             //操做數據庫  
  6.             boolean b=new UserDao().login(user.getAccount(), user.getPassword()); 
  7.             if(b){ 
  8.                 System.out.println(">> ["+user.getAccount()+"] 上線了"); 
  9.                 //告訴客戶端登錄成功  
  10.                 VQMessage m=new VQMessage(); 
  11.                 m.setType(VQMessageType.SUCCESS); 
  12.                 session.write(m); 
  13.             } 
  14.         } 
  15.     } 

最後附上測試效果:

相關文章
相關標籤/搜索