【移动开发】WIFI热点通信(二)
相信大家在上一篇中已经了解了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()
| 
 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进行连接操作,连接成功后,会在后台创建客户端,与服务器相连。主要业务设计如图所示:

核心代码:
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,目的就是为了方便自己能够更加清晰的了解整个代码的流程,当然大家也可以在此基础上进行不断的修改和完善
点击创建热点按钮:

点击搜索热点按钮:

点击列表“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
本文出自 “狂奔的蜗牛” 博客,请务必保留此出处http://smallwoniu.blog.51cto.com/3911954/1538298
【移动开发】WIFI热点通信(二)的更多相关文章
- 【移动开发】WIFI热点通信(一)
		
之前调查过Android中WIFI模块的使用,也写过两篇学习总结的文章(http://smallwoniu.blog.51cto.com/3911954/1334951),后来发现DEMO里面还是有许 ...
 - Android 开发 创建WiFi、WiFi热点 ---开发集合
		
WIFI 权限 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> < ...
 - Android WiFi开发教程(一)——WiFi热点的创建与关闭
		
相对于BlueTooth,WiFi是当今使用最广的一种无线网络传输技术, 几乎所有智能手机.平板电脑和笔记本电脑都支持Wi-Fi上网.因此,掌握基本的WiFI开发技术是非常必要的.本教程将围绕一个小D ...
 - Android WiFi开发教程(三)——WiFi热点数据传输
		
在上一篇文章中介绍了WiFi的搜索和连接,如果你还没阅读过,建议先阅读上一篇Android WiFi开发教程(二)——WiFi的搜索和连接.本篇接着简单介绍手机上如何通过WiFi热点进行数据传输. 跟 ...
 - Android WiFi/WiFi热点开发总结
		
首先看一下WiFi的自我介绍: Wi-Fi是一种允许电子设备连接到一个无线局域网(WLAN)的技术,通常使用2.4G UHF或5G SHF ISM 射频频段.连接到无线局域网通常是有密码保护的:但也可 ...
 - android 基于wifi模块通信开发
		
这篇文章主要是我写完手机与wifi模块通信后所用来总结编写过程的文章,下面,我分几点来说一下编写的大概流程. 一.拉出按钮控件并设置它的点击事件 二.设置wifi权限 三.打开和关闭wifi 四.扫描 ...
 - android  wifi热点 socket通信
		
1.首先建立wifi热点服务器 wifi客户端连接 2.开启一个子线程循环监听某个端口,进行数据流输入输出 /* 服务器 接收数据 */ class Receiver extends Thread ...
 - Android开发之扫描附近wifi热点并列表显示
		
近期项目中用到了wifi模块.今天做一个简单的总结. 參考:http://www.2cto.com/kf/201310/253617.html 1.如何获取wifi对象并进行操作 要操作WIFI设备, ...
 - 办公开发环境(外接显示屏,wifi热点)
		
笔记本电脑怎样外接显示器 https://jingyan.baidu.com/article/3c48dd34495247e10ae35879.html?qq-pf-to=pcqq.c2c 怎样在Wi ...
 
随机推荐
- vs2012快捷键
			
(1)自己整理的使用频率最高的快捷键(建议大家亲身体验一下!这样才会在潜移默化中运用得到!) (这里省去了很多大家闭上眼都会操作的什么Ctrl+S 等等操作 给出的大多是不常用但是很有用的快捷键组合! ...
 - Shell 脚本编程笔记(一) Hello Shell
			
最近不断在接触Linux操作系统,对它一个终端走天下的特性感到十分新奇和伟大.同时也被各种命令折磨的死去活来...公司的一个老同事给我讲,在公司的极品geek宅都是只用一个黑黑的框完成一切的.结果我一 ...
 - 【USACO 1.4.2】时钟
			
[题目描述] 考虑将如此安排在一个 3 x 3 行列中的九个时钟: |-------| |-------| |-------| | | | | | | | |---O | |---O | | O | ...
 - [置顶] css 背景透明,文字不透明,alpha滤镜,opacity,position:relative;
			
都知道,在alpha滤镜下,背景透明了,里面的文字也会跟随透明,我们可以设置内容的position为relative可以解决这个问题 但是在position为absolute这么做却没有效果,怎么解决 ...
 - asp.net使用Mysql乱码处理
			
在asp.net与mysql数据库打交道的时候,由于配置的问题,会遇到自己写的方法在读取数据库中数据的时候,英文,数字可以正常通过,但是中文就无法通过,以登录为例(方法略),当输入英文用户名的时候可以 ...
 - Mybatis3.0防止SQL注入
			
一.什么是SQL注入 引用搜狗百科: SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如很多影视网站泄露VIP会员密码大 ...
 - 多项式求和 AC 杭电
			
多项式求和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
 - hdu3949
			
XOR Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
 - 001Spring4.2基本环境搭建
			
1:工程目录以及依赖jar包如下,如果缺少某些jar包在weblogic控制台下面会有提示 2:applicationContext.xml配置文件 <?xml version="1. ...
 - 不通用版(从SVN取版本,通过MAVEN生成JAVA包,通过SALTSTACK传送到远程服务器并自动重启TOMCAT服务)PYTHON代码
			
从昨晚写到今天啊, 第一版测试成功了. PHP和JAVA的更新相对来说,PHP的自动化更新是简单多啦~~ 当然,这只是运维工作当中的一环~~ #!/usr/bin/env python # -*- c ...