這幾天剛學期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