* UDP服务器
* <p> UDP说明:
* <p>UDP是无连接的通信协议,本质上不分服务端和客户端,两个段都可以对方当作服务器。
* <p> Java版本的可使用DatagramSocket接口实现,关键函数说明:
* <p> .bind(): 表示监听,监听本机端口(任意定义),增加本地地址表明指明本地网卡;
* <p> .send(): 表示发送数据,每个发送的数据包都要指明发送目的服务器地址和端口号;
* <p> .receive(): 表示接收数据,每个接收数据包都要指明接收源服务器地址和端口号;
* <> 笔记本开热点,就是新建独立网卡,组成局域网,局域网内设备可以相互通信,接收发送数据,发送方需要指明地址。
* <p>使用方法:
* <p>1.笔记嗯电脑开启局域网:
* <p>本机开启WiFi热点,在cmd中ipconfig, 查看本机热点IP,如下:
* <p>2. 查看本机局域网IP:
* <p>无线局域网适配器 本地连接* 10:
* <p>
* <p> 连接特定的 DNS 后缀 . . . . . . . :
* <p> 本地链接 IPv6 地址. . . . . . . . : fe80::e4xx:93xx:47xx:xxx%4
* <p> IPv4 地址 . . . . . . . . . . . . : 192.168.137.1 //这个就是热点局域网
* <p> 子网掩码 . . . . . . . . . . . . : 255.255.255.0
* <p> 默认网关. . . . . . . . . . . . . :
* <p> 3. 手机连上局域网wifi热点,
* <p> 在笔记本电脑上热点设备列表可以看到手机或者移动设备的名称和IP,也可以把其他机器当作服务器,对应IP就行。
* <p> 4. 笔记本上运行server服务,监听本机地址端口(本地端口随意定义只要不重复就行):
* <p> // 设置自己的地址和端口号 用于相互通信,增加本地地址表明指明网卡(开热点就是新建独立网卡,组成局域网)
* <p> boundAddr = new InetSocketAddress("192.168.137.1", "9000");
* <p> log("bind: boundAddr=" + boundAddr);
* <p> sServerSocket.bind(boundAddr);
* <p> 5. 客户端UDP程序把运行server服务的地址和端口当作远端服务器地址,运行就可以实现相互发数据了。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
package com.hulk.udp.test.server; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress; import com.hulk.util.HexUtils; import com.hulk.util.HulkTimeUtils; import com.hulk.util.TextUtils; import com.hulk.util.UdpDataUtils; /** * UDP服务器 * <p> UDP说明: * <p>UDP是无连接的通信协议,本质上不分服务端和客户端,两个段都可以对方当作服务器。 * <p> Java版本的可使用DatagramSocket接口实现,关键函数说明: * <p> .bind(): 表示监听,监听本机端口(任意定义),增加本地地址表明指明本地网卡; * <p> .send(): 表示发送数据,每个发送的数据包都要指明发送目的服务器地址和端口号; * <p> .receive(): 表示接收数据,每个接收数据包都要指明接收源服务器地址和端口号; * <> 笔记本开热点,就是新建独立网卡,组成局域网,局域网内设备可以相互通信,接收发送数据,发送方需要指明地址。 * <p>使用方法: * <p>1.笔记嗯电脑开启局域网: * <p>本机开启WiFi热点,在cmd中ipconfig, 查看本机热点IP,如下: * <p>2. 查看本机局域网IP: * <p>无线局域网适配器 本地连接* 10: * <p> * <p> 连接特定的 DNS 后缀 . . . . . . . : * <p> 本地链接 IPv6 地址. . . . . . . . : fe80::e4xx:93xx:47xx:xxx%4 * <p> IPv4 地址 . . . . . . . . . . . . : 192.168.137.1 //这个就是热点局域网 * <p> 子网掩码 . . . . . . . . . . . . : 255.255.255.0 * <p> 默认网关. . . . . . . . . . . . . : * <p> 3. 手机连上局域网wifi热点, * <p> 在笔记本电脑上热点设备列表可以看到手机或者移动设备的名称和IP,也可以把其他机器当作服务器,对应IP就行。 * <p> 4. 笔记本上运行server服务,监听本机地址端口(本地端口随意定义只要不重复就行): * <p> // 设置自己的地址和端口号 用于相互通信,增加本地地址表明指明网卡(开热点就是新建独立网卡,组成局域网) * <p> boundAddr = new InetSocketAddress("192.168.137.1", "9000"); * <p> log("bind: boundAddr=" + boundAddr); * <p> sServerSocket.bind(boundAddr); * <p> 5. 客户端UDP程序把运行server服务的地址和端口当作远端服务器地址,运行就可以实现相互发数据了。 * <p> * @author hulk * */ public class UdpServer { private static final String TAG = "UdpServer"; private static final int LOCAL_UDP_BIND_PORT = UdpConstants.UDP_LISTEN_PORT; private static final String LOCAL_UDP_BIND_IP = UdpConstants.UDP_LISTEN_IP; private static final String STOP_MSG = UdpConstants.STOP_MSG; /** * UDP的socket */ private DatagramSocket mServerSocket; /** * 本机绑定地址,通常为 InetSocketAddress 对象. */ SocketAddress mBoundAddr = null; /** * 接收数据的最大buffer */ int mUdpReceiveDataBufferSize = UdpConstants.UDP_RECEIVE_DATA_BUFFER_SIZE; boolean mStopped = false; public UdpServer() { //default } public UdpServer(InetSocketAddress boundAddr) { mBoundAddr = boundAddr; } public void setBoundAddr(InetSocketAddress boundAddr) { mBoundAddr = boundAddr; } public void setReceiveDataBufferSize(int udpReceiveDataBufferSize) { mUdpReceiveDataBufferSize = udpReceiveDataBufferSize; } /** * 连接的方法 * * @param replyMsg 发送指令 * @param iCallUdp 返回的接口数据 */ public void listen(String replyMsg, ICallUdp iCallUdp) { if (TextUtils.isEmpty(replyMsg)) { replyMsg = "$M"; } log("listen: replyMsg=" + replyMsg); log("listen: udpReceiveDataBufferSize=" + mUdpReceiveDataBufferSize); iCallUdp.start(); try { // 1. 创建服务端+端口 if (mServerSocket != null) { log("Close last mServerSocket=" + mServerSocket); mServerSocket.close(); mServerSocket = null; } mServerSocket = new DatagramSocket(null); mServerSocket.setReuseAddress(true); if(mBoundAddr == null) { // 设置自己的端口号 用于相互通信 mBoundAddr = new InetSocketAddress(LOCAL_UDP_BIND_IP, LOCAL_UDP_BIND_PORT); log("listen: Created default boundAddr=" + mBoundAddr); } log("listen: bind boundAddr=" + mBoundAddr); mServerSocket.bind(mBoundAddr); //2.服务器准备接收数据 while (!mStopped) { // 2.1 准备接收容器 byte[] receiveContainer = new byte[mUdpReceiveDataBufferSize]; // 封装成包 DatagramPacket receivedPacket = new DatagramPacket(receiveContainer, receiveContainer.length); // 接收数据,使用 DatagramSocket的实例的 receive( DatagramPacket ) 方法进行接收 log("listen: receive data waiting ..."); mServerSocket.receive(receivedPacket); // 分析数据、打印数据 byte[] receivedRawData = receivedPacket.getData(); log("listen: receivedRawData.length=" + receivedRawData.length); byte[] receivedRealData = UdpDataUtils.trimData(receivedRawData); log("listen: receivedRealData.length=" + receivedRealData.length); String receivedRealDataHex = bytesToHex(receivedRealData); log("listen: receivedRealDataHex=" + receivedRealDataHex); try { //尝试用字符串去解析 String recevedMsg = new String(receivedRealData); log("listen: received recevedMsg=" + recevedMsg); if(STOP_MSG.equals(recevedMsg)) { log("break from recevedMsg: " + recevedMsg); break; } } catch (Exception e) { loge("listen: string parsed failed: " + e); } // 2.2准备发送数据 String timeStr = HulkTimeUtils.getCurrentTimeStr(); String replyMsg2 = replyMsg + ", CurrentTime:" + timeStr; byte[] sendingData = replyMsg2.getBytes(); // 2.3. 打包(发送的地点及端口) // IP 连接的目标IP地址 // port 连接目标的 端口号 SocketAddress destAddr = receivedPacket.getSocketAddress(); log("listen: sending reply data=" + new String(sendingData)); log("listen: sending reply data destAddr=" + destAddr); DatagramPacket packet = new DatagramPacket(sendingData, sendingData.length, destAddr); // 2.4 发送返回资源 mServerSocket.send(packet); log("listen: sent reply sendingdata=" + bytesToHex(sendingData)); // 回调传接收的数据 iCallUdp.success(receivedRealData, replyMsg2); } log("listen: Finished."); } catch (Exception e) { loge("Error: " + e.toString(), e); iCallUdp.failure(e.getMessage()); } finally { // 关闭资源 closeSocket(); } } /** * 关闭资源(对方在发送数据会出现异常) */ public void closeSocket() { if(mServerSocket != null) { try { mServerSocket.close(); } catch (Exception e) { //ignored } mServerSocket = null; } } /** * 将接收到byte数组转成String字符串 * * @param bytes 接收的byte数组 * @return string字符串 */ private static String bytesToHex(byte[] bytes) { return HexUtils.bytesToHex(bytes); } private static void log(String msg) { System.out.println(TAG + ": " + msg); } private static void loge(String msg) { loge(msg, null); } private static void loge(String msg, Throwable th) { System.err.println(TAG + ": " + msg); if(th != null) { th.printStackTrace(); } } public void setStopped(boolean stopped) { mStopped = stopped; } public void stop() { mStopped = true; attemptSendStop(); } /** * 通过给自己发送数据触发receive()等待函数 */ public void attemptSendStop() { if(mServerSocket != null) { byte[] data = STOP_MSG.getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, mBoundAddr); try { // 发送返回资源 mServerSocket.send(packet); } catch (IOException e) { loge("attemptStopServer failed: " + e, e); } } } } |
完整代码下载链接: https://download.csdn.net/download/zhanghao_Hulk/87635930
from:https://blog.csdn.net/zhanghao_hulk/article/details/129880572