我的上一篇文章写的是WIFI的基本应用。基本连上WIFI之后,设备就能联网了,直接用常规的联网方式即可访问互联网(例如okhttp、httpurlconnection等)。
但是我们写个wifi应用不可能是用来联网这么简单哈。设想一下,假如我们连接wifi,但是这个wifi没有连接互联网,我们能用他来干嘛?这就涉及到区域网的应用了。
这不需要连接互联网,只要在大家连接在同一个区域网内的wifi就可以通讯,目前类似应用场景已经很多了。例如各种软件的面对面快传、各种游戏的区域网联机、还有目前常用的智能家居的家具管理、基于wifi的视频监控等等。
这里主要是针对android端,当然移植到其他平台上也可以,毕竟有了算法思路。这里打算模拟连接上wifi之后和同在一个区域网的其他用户进行聊天、传输文件等。
要想和同一个区域网内的其他客户端进行通讯,首先要做的就是找到它们啊!所以本文讲的是如何搜索同一区域网内的所有设备。
----要怎么才能做到找到区域网内的所有设备呢?
天马行空1:区域网内建立一个固定ip的服务器,一旦有新的设备连接,就给服务器发送自己的ip和端口存储起来。下线时服务器再把它移除。然后需要搜索区域网内的设备时,只需要查询服务器就行了。
条件:服务器ip不能被占用,需要一个服务器!而且感觉在移动设备上,这个方案不行啊。
天马行空2:类似天马行空1,不需要在本地建立服务器,而是在云端建立数据表...
条件:我在云端查询都需要联网了,你还跟我说不连接互联网也能通讯?
天马行空3:我一个一个ping一下...0-255多试几次嘛
条件:搜索时间那么长,看到我直接卸载这个破应用了
天马行空4:你当面告诉我ip和端口,或者生成二维码给我扫一扫(类似qq快传)嘛,然后在建立链接
条件:我有一句mmp不知道要不要讲...
有没有一种方法既不用建立服务器也不用链接互联网,更不用输入ip的方式?
那必须的啊,那就是用广播!我发一个广播,你们收到了就给我回应,这不是简单方便嘛。那怎么发广播呢?这里就涉及到UDP的应用了。关于socket通讯和udp的内容我就不多说了,还那句话不怎么了解的话先看看其他博客或者百度。
---还有一句话:我只是个Android小白,出错或者算法不够好在所难免,请大家多多指教---
思路:
搜索端:
1.建立一个UDP广播,并广播出去
2.建立接收端口,收到回应再给对方发一条确认消息(当然以后是用来约定TCP的传输端口的,这样就能进行通讯了)
2.1.接收端口循环接收,除非用户中断
响应端:
1.建立响应端口,收到广播之后响应消息
1.1循环等待响应,除非用户中断
2.如果收到的是确认消息,则根据约定的规则建立TCP连接(这个文章主要时搜索设备,所以这个没写)
同时,因为是运行在android上,我的要求是要做到 我可以搜索你也可以响应你,反之你可以搜索我也可以响应我。
如果只是一个搜索端,其他都只能是响应端,那不是c/s模型,只有一个能搜索了,这显然不太符合实际要求,所以其实每个设备都有一个响应端和一个搜索端。
这样的话到时候建立TCP连接时,会出现一个问题:到底是由谁来建立服务端?这个在之后在进行处理。
有了思路就开始撸代码了--记住本文只是做到能搜索区域网内的所有设备!
搜索端线程:
static class SearchThread extends Thread {
private boolean flag = true;
private byte[] recvDate = null;
private byte[] sendDate = null;
private DatagramPacket recvDP = null;
private DatagramSocket recvDS = null;
private DatagramSocket sendDS = null;
private Handler mHandler;
private StateChangeListener onStateChangeListener;
private int state;
private int maxDevices;//防止广播攻击,设置最大搜素数量
public static final int STATE_INIT_FINISH = 0;
public static final int STATE_SEND_BROADCAST = 1;
public static final int STATE_WAITE_RESPONSE = 2;
public static final int STATE_HANDLE_RESPONSE = 3;
public SearchThread(Handler handler, int max) {
recvDate = new byte[256];
recvDP = new DatagramPacket(recvDate, 0, recvDate.length);
mHandler = handler;
maxDevices = max;
}
public void setOnStateChangeListener(StateChangeListener onStateChangeListener) {
this.onStateChangeListener = onSta