2025-02-15

這幾天剛學期android,目前項目要求的客戶端是android平臺,所以要開始啃瞭….
服務器與客戶端的通信準備使用現有的開發框架,找瞭幾個—-mina,google 的 protobuf,smack,androidpn,Netty…
這些框架都不錯,不過最終選擇的是apache的mina框架,主要是mina在網上的資料比較全,用的也比較廣泛,再就是也適合我項目以後的擴展加入SPRING\CXF\RESTFUL WEBSERVICE等
不廢話瞭,開始把目前學習的進度開始進行整理,方便自己以後進行查閱,也給其他入門的兄弟們 參考參考。
當然,最重要的是希望大傢能夠提出並給與寶貴的經驗。
 
服務端代碼:
Java代碼    
1. package org.demo;  
2.  
3. import java.net.InetSocketAddress;  
4. import java.nio.charset.Charset;  
5.  
6. import org.apache.mina.common.IdleStatus;  
7. import org.apache.mina.common.IoAcceptor;  
8. import org.apache.mina.filter.codec.ProtocolCodecFilter;  
9. import org.apache.mina.filter.codec.textline.LineDelimiter;  
10. import org.apache.mina.filter.codec.textline.TextLineCodecFactory;  
11. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;  
12. import org.slf4j.Logger;  
13. import org.slf4j.LoggerFactory;  
14.  
15.  
16. public class Demo1Server {  
17.     private static Logger logger = LoggerFactory.getLogger(Demo1Server.class);  
18.  
19.     private static int PORT = 8989;  
20.  
21.     public static void main(String[] args) {  
22.         IoAcceptor acceptor = null;  
23.         try {  
24.               
25.             // 創建一個非阻塞的server端的Socket  
26.             acceptor = new NioSocketAcceptor();  
27.             // 設置過濾器(使用Mina提供的文本換行符編解碼器)  
28.             acceptor.getFilterChain().addLast(  
29.                     "codec",  
30.                     new ProtocolCodecFilter(new TextLineCodecFactory(Charset  
31.                             .forName("UTF-8"),  
32.                             LineDelimiter.WINDOWS.getValue(),  
33.                             LineDelimiter.WINDOWS.getValue())));  
34.               
35.             // 設置讀取數據的緩沖區大小  
36.             acceptor.getSessionConfig().setReadBufferSize(2048);  
37.             // 讀寫通道10秒內無操作進入空閑狀態  
38.             acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);  
39.             // 綁定邏輯處理器  
40.             acceptor.setHandler(new Demo1ServerHandler());  
41.             // 綁定端口  
42.             acceptor.bind(new InetSocketAddress(PORT));  
43.             logger.info("服務端啟動成功…     端口號為:" + PORT);  
44.         } catch (Exception e) {  
45.             logger.error("服務端啟動異常….", e);  
46.             e.printStackTrace();  
47.         }  
48.     }  
49. } 
 邏輯處理:
Java代碼    
1. package org.demo;  
2. import java.util.Date;  
3.  
4. import net.sf.json.JSONObject;  
5.  
6. import org.apache.mina.common.IdleStatus;  
7. import org.apache.mina.common.IoHandlerAdapter;  
8. import org.apache.mina.common.IoProcessor;  
9. import org.apache.mina.common.IoSession;  
10. import org.apache.mina.transport.socket.nio.NioProcessor;  
11. import org.slf4j.Logger;  
12. import org.slf4j.LoggerFactory;  
13.  
14. public class Demo1ServerHandler extends IoHandlerAdapter{  
15.     public static Logger logger = LoggerFactory.getLogger(Demo1ServerHandler.class);  
16.  
17.     /**  
18.     * 這個方法當一個Session 對象被創建的時候被調用。對於TCP 連接來說,連接被接受的時候  
19.     * 調用,但要註意此時TCP 連接並未建立,此方法僅代表字面含義,也就是連接的對象  
20.     * IoSession 被創建完畢的時候,回調這個方法。  
21.     * 對於UDP 來說,當有數據包收到的時候回調這個方法,因為UDP 是無連接的。  
22.     */   
23.     @Override 
24.     public void sessionCreated(IoSession session) throws Exception {  
25.         logger.info("服務端與客戶端創建連接…");  
26.     }  
27.  
28.     /**  
29.     * 這個方法在連接被打開時調用,它總是在sessionCreated()方法之後被調用。對於TCP 來  
30.     * 說,它是在連接被建立之後調用,你可以在這裡執行一些認證操作、發送數據等。  
31.     */   
32.     @Override 
33.     public void sessionOpened(IoSession session) throws Exception {  
34.         logger.info("服務端與客戶端連接打開…");  
35.     }  
36.  
37.     /**  
38.     * 接收到消息時調用的方法,也就是用於接收消息的方法,一般情況下,message 是一個  
39.     * IoBuffer 類,如果你使用瞭協議編解碼器,那麼可以強制轉換為你需要的類型。  
40.     */   
41.     @Override 
42.     public void messageReceived(IoSession session, Object message)  
43.             throws Exception {  
44.         /* 
45.          String msg = message.toString(); 
46.         //讀取數據 
47.         logger.info("服務端接收到的數據為:" + msg+"客戶端ip:"+session.getLocalAddress()); 
48.         if ("bye".equals(msg)) { // 服務端斷開連接的條件 
49.             session.close(); 
50.         } 
51.         Date date = new Date(); 
52.         session.write(date);*/ 
53.         JSONObject jsonObject = JSONObject.fromObject(message.toString());  
54.         String username;   
55.         String sex;   
56.         String qq;   
57.         String score;   
58.         String nickname;  
59.         username = jsonObject.getString("username");   
60.         sex = jsonObject.getString("sex");   
61.         qq = jsonObject.getString("QQ");   
62.         score = jsonObject.getString("Min.score");  
63.         nickname = jsonObject.getString("nickname");  
64.         int state = login(username);  
65.         String msg = "登錄成功!";  
66.         if(state == 0){  
67.             msg = "登錄失敗!";  
68.         }  
69.         logger.info("用戶:" + username + msg);  
70.           
71.         //模擬登陸  
72.         if ("bye".equals(nickname)) { // 服務端斷開連接的條件  
73.             session.close();  
74.         }  
75.         //Date date = new Date();  
76.         session.write(state);  
77.     }  
78.  
79.     //驗證用戶名 與 密碼  
80.         public int login(String message){  
81.             if("sysadmin".equals(message)){  
82.                 return 1;  
83.             }  
84.             return 0;  
85.         }  
86.           
87.     /**  
88.     * 當發送消息成功時調用這個方法,註意這裡的措辭,發送成功之後,  
89.     * 也就是說發送消息是不能用這個方法的。  
90.     */   
91.     @Override 
92.     public void messageSent(IoSession session, Object message) throws Exception {  
93.         logger.info("服務端發送信息成功…");  
94.     }  
95.  
96.     /**  
97.     * 對於TCP 來說,連接被關閉時,調用這個方法。  
98.     * 對於UDP 來說,IoSession 的close()方法被調用時才會毀掉這個方法。  
99.     */   
100.     @Override 
101.     public void sessionClosed(IoSession session) throws Exception {  
102.         logger.info("服務端連接已經失效");  
103.     }  
104.  
105.     /**  
106.     * 這個方法在IoSession 的通道進入空閑狀態時調用,對於UDP 協議來說,這個方法始終不會  
107.     * 被調用。  
108.     */   
109.     @Override 
110.     public void sessionIdle(IoSession session, IdleStatus status)  
111.             throws Exception {  
112.         logger.info("服務端進入空閑狀態…");  
113.     }  
114.  
115.     /**  
116.     * 這個方法在你的程序、Mina 自身出現異常時回調,一般這裡是關閉IoSession。  
117.     */   
118.     @Override 
119.     public void exceptionCaught(IoSession session, Throwable cause)  
120.             throws Exception {  
121.         logger.error("服務端發送異常…", cause);  
122.     }  
123.  
124. } 
 客戶端代碼:
Java代碼    
1. package org.demo;  
2.  
3. import java.net.InetSocketAddress;  
4. import java.nio.charset.Charset;  
5. import java.util.Timer;  
6. import java.util.TimerTask;  
7.  
8. import org.apache.mina.common.ConnectFuture;  
9. import org.apache.mina.common.IoConnector;  
10. import org.apache.mina.common.IoSession;  
11. import org.apache.mina.filter.codec.ProtocolCodecFilter;  
12. import org.apache.mina.filter.codec.textline.LineDelimiter;  
13. import org.apache.mina.filter.codec.textline.TextLineCodecFactory;  
14. import org.apache.mina.transport.socket.nio.NioSocketConnector;  
15. import org.json.JSONException;  
16. import org.json.JSONObject;  
17. import org.slf4j.Logger;  
18. import org.slf4j.LoggerFactory;  
19.  
20. import android.app.Activity;  
21. import android.content.Context;  
22. import android.os.Bundle;  
23. import android.os.Handler;  
24. import android.os.HandlerThread;  
25. import android.os.Message;  
26. import android.view.View;  
27. import android.view.View.OnClickListener;  
28. import android.widget.Button;  
29. import android.widget.EditText;  
30. import android.widget.Toast;  
31.  
32. /** 
33.  * @author wangmiao 
34.  * @version 創建時間:2012-4-24 下午10:57:53 簡單說明 
35.  */ 
36. public class HelloWorld2 extends Activity {  
37.     private static Logger logger = LoggerFactory.getLogger(HelloWorld2.class);  
38.     private static String HOST = "192.168.1.100";  
39.  
40.     private static int PORT = 8989;  
41.     private static String LOGIN_NAME = "";  
42.  
43.     public HelloWorld2() {  
44.  
45.     }  
46.     Handler handler = new Handler();  
47.  
48.  
49.     @Override 
50.     protected void onCreate(Bundle savedInstanceState) {  
51.         // TODO Auto-generated method stub  
52.         super.onCreate(savedInstanceState);  
53.         setContentView(R.layout.main);  
54.         System.out.println(1);  
55.         /* 
56.          * new Thread() { public void run() { socketServer(); } }.start(); 
57.          */ 
58.         Button btn = (Button) findViewById(R.id.button1);  
59.         btn.setOnClickListener(new OnClickListener() {  
60.             EditText name = (EditText) findViewById(R.id.username);  
61.               
62.             @Override 
63.             public void onClick(View v) {  
64.                 // TODO Auto-generated method stub  
65.                 //name.setText("sysadmin"); 設置初始值  
66.                 final Handler myHandler = new Handler(){  
67.                     int i = 0;  
68.                     @Override 
69.                     public void handleMessage(Message msg) { //該線程位於主線程  
70.                         // TODO Auto-generated method stub  
71.                         //如果該消息是本程序所發送的  
72.                         if(msg.what == 0x1233){  
73.                             //主線程裡面 顯示操作  
74.                             i++;  
75.                             showToast("第"+i+"次連接開始….");  
76.                         }  
77.                     }  
78.                 };  
79.                 //定義一個計時器,讓該計時器周期性的執行指定任務 TimerTask對象的本質就是啟動一條新線程  
80.                 new Timer().schedule(new TimerTask()  
81.                 {  
82.                     @Override 
83.                     public void run() {  
84.                         //新啟動的線程無法訪問該Activity裡的組件  
85.                         //所以需要通過Handler發送消息  
86.                         // TODO Auto-generated method stub  
87.                         Message msg = new Message();  
88.                         msg.what = 0x1233;  
89.                         //發送消息  
90.                         myHandler.sendMessage(msg);  
91.                           
92.                         LOGIN_NAME = name.getText().toString();  
93.                         //在子線程裡面發送請求   
94.                         socketServer();  
95.                     }  
96.                 },0,10000);  
97.                 //  
98.                 /*// 壓力測試 10s秒鐘 執行一次 
99.                 while(true){ 
100.                     new Thread(){ 
101.                         public  void run(){ 
102.                             socketServer(); 
103.                         } 
104.                     }.start(); 
105.                     try { 
106.                         Thread.sleep(10000); 
107.                     } catch (InterruptedException e) { 
108.                         // TODO Auto-generated catch block 
109.                         e.printStackTrace(); 
110.                     } 
111.                 }*/ 
112.             }  
113.         });  
114.         System.out.println(1000);  
115.     }  
116.  
117.  
118.     public  void showToast(final String text) {  
119.           handler.post(new Runnable() {  
120.            @Override 
121.            public void run() {  
122.             Toast.makeText(getApplicationContext(), text,  
123.               Toast.LENGTH_SHORT).show();  
124.  
125.            }  
126.           });  
127.     }  
128.  
129.     public void socketServer() {  
130.         // 創建一個非阻塞的客戶端程序  
131.         System.out.println(2);  
132.         IoConnector connector = new NioSocketConnector();  
133.         // 設置鏈接超時時間  
134.         System.out.println(3);  
135.         connector.setConnectTimeout(5);  
136.         System.out.println(4);  
137.         // 添加過濾器 www.aiwalls.com  
138.         connector.getFilterChain().addLast(  
139.                 "codec",  
140.                 new ProtocolCodecFilter(new TextLineCodecFactory(Charset  
141.                         .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),  
142.                         LineDelimiter.WINDOWS.getValue())));  
143.         // 添加業務邏輯處理器類  
144.         connector.setHandler(new Demo1ClientHandler());  
145.         IoSession session = null;  
146.         try {  
147.             System.out.println(5);  
148.             System.out.println(HOST + "|" + PORT);  
149.             // 這裡是異步操作 連接後立即返回  
150.             ConnectFuture future = connector.connect(new InetSocketAddress(  
151.                     HOST, PORT));// 創建連接  
152.             System.out.println(6);  
153.             future.awaitUninterruptibly();// 等待連接創建完成   
154.             System.out.println(7);  
155.             session = future.getSession();// 獲得session  
156.             // session.setAttribute(arg0, arg1)  
157.             String jsonStr = "{\"people\":[" 
158.                     + "{ \"firstName\": \"問你t\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ," 
159.                     + "{ \"firstName\": \"Brett\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ,] } ";  
160.             JSONObject json = createJSONObject();  
161.  
162.             // 根據key返回一個字符串  
163.             // //String username = json.getString("username");  
164.             // System.out.println("username==>"+username);  
165.             System.out.println(8);  
166.             session.write(json);// 發送消息  
167.             System.out.println(9);  
168.               
169.              session.getCloseFuture().awaitUninterruptibly();// 等待連接斷開  
170.              connector.dispose();  
171.              System.out.println(Demo1ClientHandler.ini);  
172.              showToast(Demo1ClientHandler.ini);  
173.         } catch (Exception e) {  
174.             showToast("客戶端鏈接異常,請檢查網絡");  
175.             logger.error("客戶端鏈接異常…", e);  
176.         }  
177.           
178.     }  
179.  
180.     public static JSONObject createJSONObject() {  
181.         JSONObject jsonObject = new JSONObject();  
182.         try {  
183.             jsonObject.put("username", LOGIN_NAME);  
184.             jsonObject.put("sex", "男");  
185.             jsonObject.put("QQ", "413425430");  
186.             jsonObject.put("Min.score", new Integer(99));  
187.             jsonObject.put("nickname", "夢中心境");  
188.         } catch (JSONException e) {  
189.             // TODO Auto-generated catch block  
190.             e.printStackTrace();  
191.         }  
192.         return jsonObject;  
193.     }  
194. } 
wangmiao 寫道
這裡客戶端運用瞭 Handler消息的傳遞機制,主要是為瞭解決android應用的多線程問題–Android平臺不允許Activity新啟動的線程訪問該Activity裡的界面組件,這樣就會導致新啟動的線程無法改變界面組件的屬性值。
Handler類的主要作用有兩個:1.新啟動的線程中發送消息 2.在線程中獲取、處理消息
具體的關於Handler類的的使用去看相關的幫助說明。
 
 
 
邏輯處理:
Java代碼    
1. package org.demo;  
2.  
3. import org.apache.mina.common.IdleStatus;  
4. import org.apache.mina.common.IoHandlerAdapter;  
5. import org.apache.mina.common.IoSession;  
6. import org.slf4j.Logger;  
7. import org.slf4j.LoggerFactory;  
8.  
9.  
10. public class Demo1ClientHandler extends IoHandlerAdapter {  
11.     private static Logger logger = LoggerFactory  
12.             .getLogger(Demo1ClientHandler.class);  
13.  
14.     static String ini = "";  
15.     @Override 
16.     public void messageReceived(IoSession session, Object message)  
17.             throws Exception {  
18.         System.out.println(message);  
19.         System.out.println(11);  
20.         String msg = message.toString();  
21.         String info = "";  
22.         if ("1".equals(msg)) {  
23.             // session.close(); //用戶登錄成功 關閉連接  
24.             info = "登錄成功";  
25.         } else {  
26.             info = "登錄失敗";  
27.         }  
28.         ini = info;  
29.         session.setAttribute("state", info);  
30.         session.close();  
31.         System.out.println(12);  
32.     //   final HelloWorld h = new HelloWorld();  
33.         // h.DisplayToast(info);  
34.         logger.info("客戶端接收到的信息為:" + msg);  
35.     }  
36.  
37.  
38.  
39.     @Override 
40.     public void exceptionCaught(IoSession session, Throwable cause)  
41.             throws Exception {  
42.  
43.         logger.error("客戶端發生異常…", cause);  
44.     }  
45.  
46.     @Override 
47.     public void sessionCreated(IoSession arg0) throws Exception {  
48.         // TODO Auto-generated method stub  
49.     }  
50.  
51.     @Override 
52.     public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception {  
53.         // TODO Auto-generated method stub  
54.     }  
55.  
56.     /**  
57.     * 這個方法在連接被打開時調用,它總是在sessionCreated()方法之後被調用。對於TCP 來  
58.     * 說,它是在連接被建立之後調用,你可以在這裡執行一些認證操作、發送數據等。  
59.     */    
60.     @Override 
61.     public void sessionOpened(IoSession arg0) throws Exception {  
62.         logger.info("ok", "i am ready!");  
63.         System.out.println(6);  
64.     }  
65. } 

 
摘自 wmiao89620

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *