最近无意间看到微信小程序里多了个关于UDP的API,一时间感慨良多。想当初,小程序刚发布,想开发个局域网通信的程序,翻遍API居然没有,http/websocket要求域名,蓝牙只支持ble,郁闷得还专门找客服反馈。。。网上找了下,也没看到什么文章,那我就写个总结,顺便纪念下。
既然是通信,那么至少得有两个参与者,一端已经确定微信小程序了,另一端来点不一样的,Android吧(其实是作者Android出身~~)。
局域网通信,首先得有对方的地址,也就是ip和port,所以第一步就是设备搜索。所幸,小程序里有个mDNS的API,Android里也有个NSDManager(也就是mDNS的实现)。不清楚mDNS的,自行百度,笔者懒。。。
这样方案就确定了,通过mDNS发现设备,UDP通信。这里我们以Android端为Server,小程序为client,作为例子讲解。
mDNS发现设备
Android Server端
只需要调用NSDManager.registerService就实现了mDNS的注册:
private void mDNSRegister(){ mRegistrationListener = new NsdManager.RegistrationListener() { @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.i(TAG,"onRegistrationFailed "); } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.i(TAG,"onUnregistrationFailed "); } @Override public void onServiceRegistered(NsdServiceInfo serviceInfo) { Log.i(TAG,"onServiceRegistered "); } @Override public void onServiceUnregistered(NsdServiceInfo serviceInfo) { Log.i(TAG,"onServiceUnregistered "); } }; mNsdManager = (NsdManager) getSystemService(NSD_SERVICE); NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName("test"); serviceInfo.setPort(CHAT_PORT);//udp通信使用的端口号,通过mDNS发出去 serviceInfo.setServiceType("_test._udp.");//客户端发现服务器是需要对应的这个Type字符串 mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); }当然要记得在使用完后注销掉:
private void mDNSUnregister() { mNsdManager.unregisterService(mRegistrationListener); }小程序 client端
开启设备搜索
startDiscovery: function () { wx.startLocalServiceDiscovery({ serviceType: '_test._udp.',//对应上面server端注册的type success: function (res) { console.log(res) }, fail: function (err) { console.log(err) }, complete: function () { console.log('complete') } }) }搜索到设备
onLocalService: function () { let that = this // 监听服务发现事件 wx.onLocalServiceFound(function (obj) { console.log(obj) serviceList.push(obj); that.setData({ lists: serviceList }) })停止搜索
stopDiscovery: function () { let that = this wx.stopLocalServiceDiscovery({ success: function () { that.showTips('停止搜索成功', 'success') serviceList = [] resolveFailList = [] that.setData({ lists: [], resolveFailList: [] }) }, fail: function () { that.showTips('停止搜索失败,请重试!') }, complete: function () { console.log('stopDiscovery complete') } }) }这样设备发现这一步就基本完成了。接下来就是udp通信了。
udp通信
Android Server端
private void startUdpListener(){ if(running){ return; } try { socket = new DatagramSocket(CHAT_PORT);//绑定端口,暂未考虑端口占用,实际使用中可以使用循环增加端口号到方法来避免端口占用 packet = new DatagramPacket(buffer,BUFFER_SIZE); } catch (SocketException e) { e.printStackTrace(); return; } udpListenerThread = new Thread(new Runnable() { @Override public void run() { while (running){ try { socket.receive(packet); } catch (IOException e) { e.printStackTrace(); } if (packet == null || packet.getLength() == 0) { Log.e(TAG, "无法接收UDP数据或者接收到的UDP数据为空"); continue; } String strReceive = new String(packet.getData(), 0, packet.getLength()); String ip = packet.getAddress().getHostAddress(); int port = packet.getPort(); Log.d(TAG, strReceive + " from " + ip + ":" + port); sendUdpMsg(ip,port,"received you message:"+strReceive); } } }); running = true; udpListenerThread.start(); } //发送udp消息private void sendUdpMsg(String ip,int port,String message){ InetAddress targetAddress = null; try { targetAddress = InetAddress.getByName(ip); DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), targetAddress, port); socket.send(packet); } catch (Exception e) { e.printStackTrace(); } }上面代码主要内容是开启一个线程,循环监听消息,收到消息后发送一个回复消息。
小程序 client端
var ip = this.data.lists[index].ip; var port = this.data.lists[index].port; const udp = wx.createUDPSocket(); udp.bind(); udp.send({ address: ip, port: port, message: "hello world!" }); udp.onMessage(function (res){ //字符串转换,很重要 let unit8Arr = new Uint8Array(res.message); let encodedString = String.fromCharCode.apply(null, unit8Arr); let message = decodeURIComponent(escape((encodedString))); that.setData({ receiveMessage: message, fromIp: res.remoteInfo.address }) });上面代码主要内容是发送一个消息,并监听收到的消息
以上就是微信小程序和Android App局域网通信的重要部分了,完整代码已经整理好放在码云上了,有需要的可以自行下载。
https://gitee.com/yygood1/wechat_demo_udp













