您好,登錄后才能下訂單哦!
相信大家在上一篇中已經了解了Android中WIFI熱點通信的相關操作知識(http://smallwoniu.blog.51cto.com/3911954/1536126),今天我們將在上一篇代碼基礎之上進行Socket編程,實現一個簡單的多人聊天室功能,以達到熱點網絡上的通信目的。
首先,我們先來看一張最終效果圖:
<=======>
(說明:由于目前作服務器端的手機,只是實現了數據的接收和轉發,自己發送的數據并未顯示到自己的界面上,還需大家完善。。。)
一.框架搭建
在上一章的代碼基礎上,新增加了四個類:
GameServer:服務器端實現。
SocketClient:客戶端實現類。
ChatAdapter:聊天列表適配器。
ChatMessage:聊天信息實體。
GroupChatActivity:聊天室Acitivity。
1.1.相關類圖
在熱點連接成功后,開始聊天通信過程,服務器端與客戶端的類實現如下圖所示:
1.2.說明:
服務端:套接字GameServer,端口和套接字監聽函數beginListen(),接收數據的函數serverAcceptClientMsg(),發送數據的函數sendMsgToAllCLients,以及網絡通訊流BufferedReader。
客戶端:套接字SocketClient,套接字連接函數startConnServer(),接收數據的函數acceptGameServerMsg(),發送數據的函數sendMsg()。
前面提到過創建熱點成功后,會自動在當前手機后臺創建GameServer,同時開啟線程監聽端口并等待連接,當其余玩家成功連接上熱點后,每個手機客戶端后臺對應會創建一個獨立的Socket,用于發送和接收消息。在客戶端中通過client.getInputStream()接收數數據,ClientMsgListener.handlerHotMsg(getSMsg)將數據反映到UI界面上,最終實現了客戶端接收服務器端數據刷新UI界面的功能。
二.通信模塊
2.1.服務器端
由于軟件的通信載體是在手機上,所以在創建完成熱點之后,在后臺也同時創建了游戲的服務器,開啟了監聽PORT線程,等待其他客戶端連接。這樣設計的目的是為了在當有其他手機端連接上指定WIFI熱點時就與后臺服務器端進行了連接,即實現了TCP/IP通訊前期準備。主要業務設計如圖所示:
核心代碼:
beginListenandAcceptMsg()
/** init server to listen **/ public void beginListenandAcceptMsg() { new Thread(new Runnable() { @Override public void run() { try { // init server mServerSocket = new ServerSocket(); mServerSocket.setReuseAddress(true); InetSocketAddress address = new InetSocketAddress(mPort); mServerSocket.bind(address); mServerMsgListener.handlerHotMsg(Global.INT_SERVER_SUCCESS); Log.i(TAG, "server =" + mServerSocket); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //server accept from socket msg if(mServerSocket != null) { while(onGoinglistner) { try { Socket socket = mServerSocket.accept(); if(socket != null) { if(!socketQueue.contains(socket)) { socketQueue.add(socket); count++; //記錄連接人數 } Log.i(TAG, "接收客戶端消息" + socket); serverAcceptClientMsg(socket); } } catch (IOException e) { e.printStackTrace(); } } } } }).start(); }
serverAcceptClientMsg()
/** * accept from socket msg * @param socket */ private void serverAcceptClientMsg(final Socket socket) { new Thread(new Runnable(){ @Override public void run() { while(!socket.isClosed()) { try { //此處可以根據連接的客戶端數量count做一些數據分發等操作。 //接收客戶端消息 in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); String str = in.readLine(); if(str == null || str.equals("")) { break; } Log.i(TAG, "client" + socket + "str =" + str); mServerMsgListener.handlerHotMsg(str); } catch (Exception e) { e.printStackTrace(); } } } }).start(); }
sendMsg()
/**send msg to the socket**/ public void sendMsg(Socket client, String chatMsg) { Log.i(TAG, "into sendMsg(final Socket client,final ChatMessage msg) msg = " + chatMsg); PrintWriter out = null; if (client.isConnected()) { if (!client.isOutputShutdown()) { try { out = new PrintWriter(client.getOutputStream()); out.println(chatMsg); out.flush(); Log.i(TAG, "into sendMsg(final Socket client,final ChatMessage msg) msg = " + chatMsg + " success!"); } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "into sendMsg(final Socket client,final ChatMessage msg) fail!"); } } } Log.i(TAG, "out sendMsg(final Socket client,final ChatMessage msg) msg = " + chatMsg); }
2.2.客戶端
這里的客戶端建立指的是當其他手機在該軟件的WIFI管理界面上,點擊可用WIFI列表中指定的WIFI進行連接操作,連接成功后,會在后臺創建客戶端,與服務器相連。主要業務設計如圖所示:
核心代碼:
connServerandAcceptMsg()
/**after hot pot created and connected successful , start connect GameServer**/ public void connServerandAcceptMsg() { Log.i(TAG, "into connectServer()"); new Thread(new Runnable() { @Override public void run() { try { client = new Socket(site, port); Log.i(TAG, "Client is created! site:" + site + " port:" + port); //callback mClientMsgListener.handlerHotMsg(Global.INT_CLIENT_SUCCESS); //accept msg from GameServer acceptGameServerMsg(); } catch (UnknownHostException e) { e.printStackTrace(); mClientMsgListener.handlerErorMsg(Global.INT_CLIENT_FAIL); } catch (IOException e) { e.printStackTrace(); mClientMsgListener.handlerErorMsg(Global.INT_CLIENT_FAIL); } } }).start(); Log.i(TAG, "out connectServer()"); }
acceptGameServerMsg()
/**accept msg from GameServer**/ private void acceptGameServerMsg() { new Thread(new Runnable() { @Override public void run() { while(onGoinglistner){ if(client != null && client.isConnected()) { if(!client.isInputShutdown()) { try { in = new BufferedReader(new InputStreamReader(client.getInputStream())); String getSMsg = in.readLine(); Log.i(TAG, "into acceptMsg() SMsg =" + getSMsg); if(getSMsg != null || !getSMsg.equals("")) { //callback mClientMsgListener.handlerHotMsg(getSMsg); } } catch (IOException e) { e.printStackTrace(); } } } } } }).start(); }
sendMsg()
/**send msg to GameServer**/ public String sendMsg(final String chatMsg) { Log.i(TAG, "into sendMsgsendMsg(final ChatMessage msg) msg =" + chatMsg); new Thread(new Runnable() { @Override public void run() { try { if (client != null && client.isConnected()) { if (!client.isOutputShutdown()) { PrintWriter out = new PrintWriter(client.getOutputStream()); out.println(chatMsg); // out.println(JsonUtil.obj2Str(msg)); Log.i(TAG, "成功發送msg =" + chatMsg); out.flush(); } } } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "client snedMsg error!"); } } }).start(); return ""; }
以上兩大部分為Socket編程部分,為了能夠將數據反映到UI 前臺,這里我們將每次線程接收到的數據先以接口回調方法( mClientMsgListener.handlerHotMsg(getSMsg);)的形式傳遞,在其對應的方法中再利用Handler消息機制將數據發送到各自對應的Handler中,最后根據邏輯將其反映到UI上,以上就是代碼的大體流程。
2.3.通信過程
下載過完整代碼的朋友就會發現代碼中許多重要的方法中我加入了Log,目的就是為了方便自己能夠更加清晰的了解整個代碼的流程,當然大家也可以在此基礎上進行不斷的修改和完善
點擊創建熱點按鈕:
點擊搜索熱點按鈕:
點擊列表“WIFI-TEST”進行連接
三.總結
1.此案例由于是從本人畢業設計中扒下來的,可能現在有些地方代碼框架設計的不是很合理,如:GroupChatActivity就是為了方便實現聊天功能后添加的,大家在學習完之后可以在Activity跳轉時的基礎上,進一步按照自己的邏輯來實現一些東西。
2.UI如何更新?
服務器端只是實現數據轉發,未對自己發送數據進行顯示,了解了整個代碼的同學可能已經發現不論是Server還是Client端,在接收到數據之后,我們通過各自的監聽器(mServerMsgListener,mClientMsgListener)來回調對應的方法(handlerHotMsg,handlerErrorMsg),在方法中我們將數據添加msg.obj中,最終以消息傳遞的方式發送到各自對應的handler中(clientHandler,serverHandler),在那里我們就可以根據數據來更新界面。
3.題外話:
要是有人對熱點通信特別感興趣,想在此的基礎之上開發小游戲,前臺游戲繪制界面就不用多說了,我主要想說的是后臺數據部分,最好能給所有操作制定了一系列對應的數據規則,如:出牌操作:在傳輸的數據串前面加上規則字符---->“《#CARD》+數據段”,之后作為整體發送出去,這樣的話,接收方在接收到數據后可以方便的更新UI,實現對應的游戲動畫。(個人經驗,僅供參考)
×××:http://down.51cto.com/data/1856373
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。