什么是UDP协议以及它的使用优点:百度的解释是这样的:Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
- 不需要要建立连接
- 开销小
- 速度快
一:udp通信主要使用的场景:
比如设备监控,监控设备是否脱机,目前我主要是用于在同一个局域网内模拟设备给手机app发送数据,app界面需要显示该设备的一个工作情况,比如车辆的转速 工作时间 当前电量 待机 预热情况等,那么中间就有一个接收模拟设备发送过来的报文数据,以及当我接收完数据的一个显示情况,作为app端只需要接收数据,所以下面的内容主要是介绍app端接收udp的报文数据。
二:udp通信 接收数据方的流程:
- 创建Socket对象 ( DatagramSocket)
- 创建一个接收数据的包 (DatagramPacket)下面代码创建了一个接收线程 每沉睡20毫秒后receive数据
- 解析数据包 大致代码如下
private DatagramSocket receiveSocket = null;// 接收数据Socket private DatagramPacket rPacket = null; private DatagramPacket packet = null; private Thread rthread = null;// 接收数据线程
/*** 接收数据socket连接 ***/ private void connectSocket() { DisConnectSocket(); try { if (receiveSocket == null) { receiveSocket = new DatagramSocket(null); receiveSocket.setReuseAddress(true); receiveSocket.bind(new InetSocketAddress(port)); } if (rPacket == null) { rPacket = new DatagramPacket(rBuffer, rBuffer.length); } if (rthread == null) { //创建接收线程 ReceiveDataThread receiveDataThread = new ReceiveDataThread(); rthread = new Thread(receiveDataThread); rthread.start(); } } catch (Exception e) { e.printStackTrace(); ToastUtils.showShort("连接本地端口:" + localPort + "失败,异常代码:" + e.getMessage(),Toast.LENGTH_LONG); DisConnectSocket(); } }
class ReceiveDataThread implements Runnable { @Override public void run() { Boolean aBoolean = false; if(Thread.currentThread() == rthread){ while (Thread.currentThread() == rthread) { //接收报文数据 recvData(); Thread.sleep(20); } catch (Exception e) { e.printStackTrace(); } } } } }
/**** * 接收数据 * * @return */ private boolean recvData() { try { if (receiveSocket != null) { try { //设置超时时间 receiveSocket.setSoTimeout(2000); receiveSocket.receive(rPacket); // sRecvData 是接收到的报文数据 if (isRHex) { sRecvData = recvHexData(rPacket.getLength()); } else { sRecvData = new String(rPacket.getData(), currentRCodes) .trim(); } aBoolean = false; } catch (Exception e) { sRecvData = null; aBoolean = true; } } else { ToastUtils.showShort("没有连接本地端口!",Toast.LENGTH_LONG); return false; } return aBoolean; } catch (Exception e) { // ToastUtils.showShort("接收数据错误,异常代码:"+ e.getMessage(),Toast.LENGTH_LONG); return aBoolean; } }
三:我遇到的问题
当模拟设备不给app端发数据时需要清空界面数据,can转WiFi模块(模拟设备)设置的是20毫秒会发送一次数据,但udp通信是没有接收到数据会处于阻塞状态,receive();方法会一直等待数据接收,直到有数据接收到的时候就会结束阻塞,解决方法: receiveSocket.setSoTimeout(2000); 设置2s超时等待,如果2s还是没有接收到数据就抛出异常,那么就可以在catch里面去调用界面参数的清空方法。