相信大家在上一篇中已經了解了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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。