【移动开发】WIFI热点通信(二)

简介:

     相信大家在上一篇中已经了解了Android中WIFI热点通信的相关操作知识(http://smallwoniu.blog.51cto.com/3911954/1536126),今天我们将在上一篇代码基础之上进行Socket编程,实现一个简单的多人聊天室功能,以达到热点网络上的通信目的。

    首先,我们先来看一张最终效果图:


wKioL1PnXjSTfQyFAADMP7HFqUc438.jpg<=======>wKiom1PnXRuwN6UfAAEyJEArh20439.jpg

(说明:由于目前作服务器端的手机,只是实现了数据的接收和转发,自己发送的数据并未显示到自己的界面上,还需大家完善。。。)


一.框架搭建

在上一章的代码基础上,新增加了四个类:

    GameServer:服务器端实现。

    SocketClient:客户端实现类。

    ChatAdapter:聊天列表适配器。

    ChatMessage:聊天信息实体。

    GroupChatActivity:聊天室Acitivity。

1.1.相关类图

在热点连接成功后,开始聊天通信过程,服务器端与客户端的类实现如下图所示:

wKioL1PAkQzi-v20AAP9qevcyE8708.jpg

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通讯前期准备。主要业务设计如图所示:

wKiom1PAjpniy6N4AACe8Ur9PJo749.jpg

核心代码:

  •  beginListenandAcceptMsg()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  /** 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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /**
      * 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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**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进行连接操作,连接成功后,会在后台创建客户端,与服务器相连。主要业务设计如图所示:

wKioL1PAjsfhwDdxAACapz8mr18277.jpg

核心代码:

  • connServerandAcceptMsg()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**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,目的就是为了方便自己能够更加清晰的了解整个代码的流程,当然大家也可以在此基础上进行不断的修改和完善

  • 点击创建热点按钮:

wKioL1Pg7HrBZM-zAAQ-D1LavDQ087.jpg












  • 点击搜索热点按钮:

wKioL1Pg7M3BagyFAARLtpu0XOU567.jpg













  • 点击列表“WIFI-TEST”进行连接

wKiom1Pg7VuTqR64AAQ9q0ajUR4223.jpg


三.总结


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




     本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1538298,如需转载请自行联系原作者




相关文章
|
Android开发
Android获取已连接wifi的热点信息(上位机开发学习之多个界面切换编程)
Android获取已连接wifi的热点信息(上位机开发学习之多个界面切换编程)
258 0
|
物联网 Android开发
Android获取已连接wifi的热点信息
Android获取已连接wifi的热点信息
290 0
|
Ubuntu 网络协议 网络安全
i.mx287学习笔记-ubuntu虚拟机网络配置同时连接WIFI上外网和连接以太网与i.mx287开发板通信
在学习ARM嵌入式开发过程中,需要在ubuntu虚拟机下进行程序开发和编译,一般需要使用网线直连ARM开发板,或挂载NFS网络文件系统,或通过SSH 、TFTP等网络协议传输在PC端编译完的二进制文件,另一方面又需要使用ubuntu虚拟机连接外网,用来下载一些依赖包或者工具链等,本文介绍一种方法,使得ubuntu虚拟机既可以连接WIFI上外网,又可以连接ARM开发板进行其嵌入式开发。
231 0
|
安全 5G 定位技术
IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!
WiFi对于现在的家庭来说,属于司空见惯的上网方式,但很多情况下,家里房间多、空间大、杂物乱的情况下,WiFi的信号就受影响。为什么WiFi信号会受影响?什么情况下该使用何种方式组网?如何改善WiFi信号差的问题?等等,本文将通俗易懂地为你找到这些问题的答案。
175 0
IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!
|
网络安全 Android开发 Windows
如何让手机共享电脑代理网络的WIFI热点
如何让手机共享电脑代理网络的WIFI热点
3773 0
如何让手机共享电脑代理网络的WIFI热点
|
网络协议 数据安全/隐私保护 Windows
Windows Win7建立wifi热点,手机共享WIFI上网
Windows Win7建立wifi热点,手机共享WIFI上网
212 0
|
Ubuntu 数据安全/隐私保护
Ubuntu使用linux-wifi-hotspot创建WIFI热点
Ubuntu使用linux-wifi-hotspot创建WIFI热点
1675 0
Ubuntu使用linux-wifi-hotspot创建WIFI热点
|
Linux 开发工具 数据安全/隐私保护
Linux操作系统下开启wifi热点的方法
在很多场合下,网络使用是非常重要的,如果有一个Linux可以发出wifi热点,那么很多时候可以对于开发者来说是非常方便的。
1255 1
下一篇
DataWorks