溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)

發(fā)布時(shí)間:2020-07-18 12:34:06 來源:網(wǎng)絡(luò) 閱讀:7060 作者:zhf651555765 欄目:開發(fā)技術(shù)

      相信大家在上一篇中已經(jīng)了解了Android中WIFI熱點(diǎn)通信的相關(guān)操作知識(shí)(http://smallwoniu.blog.51cto.com/3911954/1536126),今天我們將在上一篇代碼基礎(chǔ)之上進(jìn)行Socket編程,實(shí)現(xiàn)一個(gè)簡單的多人聊天室功能,以達(dá)到熱點(diǎn)網(wǎng)絡(luò)上的通信目的。

    首先,我們先來看一張最終效果圖:


【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)<=======>【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)

(說明:由于目前作服務(wù)器端的手機(jī),只是實(shí)現(xiàn)了數(shù)據(jù)的接收和轉(zhuǎn)發(fā),自己發(fā)送的數(shù)據(jù)并未顯示到自己的界面上,還需大家完善。。。)


一.框架搭建

在上一章的代碼基礎(chǔ)上,新增加了四個(gè)類:

    GameServer:服務(wù)器端實(shí)現(xiàn)。

    SocketClient:客戶端實(shí)現(xiàn)類。

    ChatAdapter:聊天列表適配器。

    ChatMessage:聊天信息實(shí)體。

    GroupChatActivity:聊天室Acitivity。

1.1.相關(guān)類圖

在熱點(diǎn)連接成功后,開始聊天通信過程,服務(wù)器端與客戶端的類實(shí)現(xiàn)如下圖所示:

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)

1.2.說明:

服務(wù)端:套接字GameServer,端口和套接字監(jiān)聽函數(shù)beginListen(),接收數(shù)據(jù)的函數(shù)serverAcceptClientMsg(),發(fā)送數(shù)據(jù)的函數(shù)sendMsgToAllCLients,以及網(wǎng)絡(luò)通訊流BufferedReader。

客戶端:套接字SocketClient,套接字連接函數(shù)startConnServer(),接收數(shù)據(jù)的函數(shù)acceptGameServerMsg(),發(fā)送數(shù)據(jù)的函數(shù)sendMsg()。

前面提到過創(chuàng)建熱點(diǎn)成功后,會(huì)自動(dòng)在當(dāng)前手機(jī)后臺(tái)創(chuàng)建GameServer,同時(shí)開啟線程監(jiān)聽端口并等待連接,當(dāng)其余玩家成功連接上熱點(diǎn)后,每個(gè)手機(jī)客戶端后臺(tái)對應(yīng)會(huì)創(chuàng)建一個(gè)獨(dú)立的Socket,用于發(fā)送和接收消息。在客戶端中通過client.getInputStream()接收數(shù)數(shù)據(jù),ClientMsgListener.handlerHotMsg(getSMsg)將數(shù)據(jù)反映到UI界面上,最終實(shí)現(xiàn)了客戶端接收服務(wù)器端數(shù)據(jù)刷新UI界面的功能。


二.通信模塊


    2.1.服務(wù)器端

由于軟件的通信載體是在手機(jī)上,所以在創(chuàng)建完成熱點(diǎn)之后,在后臺(tái)也同時(shí)創(chuàng)建了游戲的服務(wù)器,開啟了監(jiān)聽PORT線程,等待其他客戶端連接。這樣設(shè)計(jì)的目的是為了在當(dāng)有其他手機(jī)端連接上指定WIFI熱點(diǎn)時(shí)就與后臺(tái)服務(wù)器端進(jìn)行了連接,即實(shí)現(xiàn)了TCP/IP通訊前期準(zhǔn)備。主要業(yè)務(wù)設(shè)計(jì)如圖所示:

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)

核心代碼:

  •  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++; //記錄連接人數(shù)
                                }
                                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 {
                    //此處可以根據(jù)連接的客戶端數(shù)量count做一些數(shù)據(jù)分發(fā)等操作。
                        //接收客戶端消息
                    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.客戶端

        這里的客戶端建立指的是當(dāng)其他手機(jī)在該軟件的WIFI管理界面上,點(diǎn)擊可用WIFI列表中指定的WIFI進(jìn)行連接操作,連接成功后,會(huì)在后臺(tái)創(chuàng)建客戶端,與服務(wù)器相連。主要業(yè)務(wù)設(shè)計(jì)如圖所示:

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)

核心代碼:

  • 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, "成功發(fā)送msg =" + chatMsg);
                            out.flush();
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "client snedMsg error!");
                }
            }
        }).start();
        return "";
    }

以上兩大部分為Socket編程部分,為了能夠?qū)?shù)據(jù)反映到UI 前臺(tái),這里我們將每次線程接收到的數(shù)據(jù)先以接口回調(diào)方法( mClientMsgListener.handlerHotMsg(getSMsg);)的形式傳遞,在其對應(yīng)的方法中再利用Handler消息機(jī)制將數(shù)據(jù)發(fā)送到各自對應(yīng)的Handler中,最后根據(jù)邏輯將其反映到UI上,以上就是代碼的大體流程。


2.3.通信過程

下載過完整代碼的朋友就會(huì)發(fā)現(xiàn)代碼中許多重要的方法中我加入了Log,目的就是為了方便自己能夠更加清晰的了解整個(gè)代碼的流程,當(dāng)然大家也可以在此基礎(chǔ)上進(jìn)行不斷的修改和完善

  • 點(diǎn)擊創(chuàng)建熱點(diǎn)按鈕:

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)












  • 點(diǎn)擊搜索熱點(diǎn)按鈕:

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)













  • 點(diǎn)擊列表“WIFI-TEST”進(jìn)行連接

【移動(dòng)開發(fā)】WIFI熱點(diǎn)通信(二)


三.總結(jié)


1.此案例由于是從本人畢業(yè)設(shè)計(jì)中扒下來的,可能現(xiàn)在有些地方代碼框架設(shè)計(jì)的不是很合理,如:GroupChatActivity就是為了方便實(shí)現(xiàn)聊天功能后添加的,大家在學(xué)習(xí)完之后可以在Activity跳轉(zhuǎn)時(shí)的基礎(chǔ)上,進(jìn)一步按照自己的邏輯來實(shí)現(xiàn)一些東西。

 

    2.UI如何更新?

     服務(wù)器端只是實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)發(fā),未對自己發(fā)送數(shù)據(jù)進(jìn)行顯示,了解了整個(gè)代碼的同學(xué)可能已經(jīng)發(fā)現(xiàn)不論是Server還是Client端,在接收到數(shù)據(jù)之后,我們通過各自的監(jiān)聽器(mServerMsgListener,mClientMsgListener)來回調(diào)對應(yīng)的方法(handlerHotMsg,handlerErrorMsg),在方法中我們將數(shù)據(jù)添加msg.obj中,最終以消息傳遞的方式發(fā)送到各自對應(yīng)的handler中(clientHandler,serverHandler),在那里我們就可以根據(jù)數(shù)據(jù)來更新界面。

 

3.題外話:

     要是有人對熱點(diǎn)通信特別感興趣,想在此的基礎(chǔ)之上開發(fā)小游戲,前臺(tái)游戲繪制界面就不用多說了,我主要想說的是后臺(tái)數(shù)據(jù)部分,最好能給所有操作制定了一系列對應(yīng)的數(shù)據(jù)規(guī)則,如:出牌操作:在傳輸?shù)臄?shù)據(jù)串前面加上規(guī)則字符---->“《#CARD》+數(shù)據(jù)段”,之后作為整體發(fā)送出去,這樣的話,接收方在接收到數(shù)據(jù)后可以方便的更新UI,實(shí)現(xiàn)對應(yīng)的游戲動(dòng)畫。(個(gè)人經(jīng)驗(yàn),僅供參考)


×××:http://down.51cto.com/data/1856373




向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI