为了网络监听的clear,以及权限问题,需要对上述代码进行一次升级。
BIO_UDP2_MessageCreator package self.v2; /** * @Description: 自定义通信数据格式(这可能是最简单的应用层协议了) * @Author: jarry */ public class MessageCreator { private static final String SN_HEADER = "收到暗号,我是(SN):"; private static final String PORT_HEADER = "发送暗号,请回电端口(PORT):"; public static String buildWithPort(int port){ return PORT_HEADER + port; } public static int parsePort(String data){ if (data.startsWith(PORT_HEADER)){ return Integer.parseInt(data.substring(PORT_HEADER.length())); } return -1; } public static String buildWithSN(String sn){ return SN_HEADER + sn; } public static String parseSN(String data){ if (data.startsWith(SN_HEADER)){ return data.substring(SN_HEADER.length()); } return null; } } BIO_UDP2_Searcher package self.v2; import java.io.IOException; import java.net.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; /** * @Description: * @Author: jarry */ public class UDPSearcher { // 监听端口号 private static final int LISTEN_PORT = 30000; public static void main(String[] args) throws IOException, InterruptedException { System.out.println("UDPSearcher Started"); Listener listener = listen(); sendBroadcast(); // 读取任意键盘信息后退出 System.in.read(); List<Device> devices = listener.getDevicesAndClose(); for (Device device : devices) { System.out.println("Device:"+device.toString()); } // 完成 System.out.println("UDPSearcher Finished"); } private static Listener listen() throws InterruptedException { System.out.println("UDPSearcher start listen."); CountDownLatch countDownLatch = new CountDownLatch(1); Listener listener = new Listener(LISTEN_PORT, countDownLatch); listener.start(); countDownLatch.await(); return listener; } /** * 用于发送广播消息 * @throws IOException */ private static void sendBroadcast() throws IOException { System.out.println("UDPSearcher sendBroadcast started."); // 作为一个搜索者(发送请求),无需指定一个端口,由系统自动分配 DatagramSocket datagramSocket = new DatagramSocket(); // 构建一份请求数据 String requestData = MessageCreator.buildWithPort(LISTEN_PORT); byte[] requestDataBytes = requestData.getBytes(); // 构建发送数据实体 DatagramPacket requestPacket = new DatagramPacket(requestDataBytes, requestDataBytes.length); // 设置目标地址(采用广播地址) requestPacket.setAddress(Inet4Address.getByName("255.255.255.255")); requestPacket.setPort(20000); // 发送构建好的消息 datagramSocket.send(requestPacket); System.out.println("start send data."); // 发送结束 System.out.println("UDPSearcher sendBroadcast finished."); datagramSocket.close(); } private static class Device { final int port; final String ip; final String sn; public Device(int port, String ip, String sn) { this.port = port; this.ip = ip; this.sn = sn; } @Override public String toString() { return "Device{" + "port=" + port + ", ip='" + ip + '\'' + ", sn='" + sn + '\'' + '}'; } } private static class Listener extends Thread{ private final int listenPort; private final CountDownLatch countDownLatch; private final List<Device> devices = new ArrayList<Device>(); private boolean done = false; private DatagramSocket ds = null; public Listener(int listenPort, CountDownLatch countDownLatch){ super(); this.listenPort = listenPort; this.countDownLatch = countDownLatch; } @Override public void run() { super.run(); // 通知已启动 countDownLatch.countDown(); // 开始实际数据监听部分 try { // 监听回送端口 ds = new DatagramSocket(listenPort); while (!done){ // 接收消息的实体 final byte[] buf = new byte[512]; DatagramPacket receivePack = new DatagramPacket(buf, buf.length); // 开始接收数据 ds.receive(receivePack); // 打印接收到的信息 String ip = receivePack.getAddress().getHostAddress(); int port = receivePack.getPort(); int dataLength = receivePack.getLength(); String data = new String(receivePack.getData(),0,dataLength); System.out.println("UDPSearcher receive form ip:" + ip + "\tport:" + port + "\tdata:" + data); String sn = MessageCreator.parseSN(data); if (sn != null){ Device device = new Device(port, ip ,sn); devices.add(device); } } }catch (Exception e){ }finally { close(); } System.out.println("UDPSearcher listner finished"); } private void close(){ if (ds != null){ ds.close(); ds = null; } } List<Device> getDevicesAndClose(){ done = true; close(); return devices; } } } BIO_UDP_Provider package self.v2; /** * @Description: * @Author: jarry */ import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.util.UUID; /** * UDP 提供者, 用于提供UDP服务 */ public class UDPProvider { public static void main(String[] args) throws IOException { String sn = UUID.randomUUID().toString(); Provider provider = new Provider(sn); provider.start(); // 读取任意字符,退出 System.in.read(); provider.exit(); } private static class Provider extends Thread { private final String sn; private boolean done = false; private DatagramSocket datagramSocket = null; public Provider(String sn){ super(); this.sn = sn; } @Override public void run() { super.run(); System.out.println("UDPProvider started."); try { // 作为一个接收者(接受请求),需要指定一个端口用来接收消息 datagramSocket = new DatagramSocket(20000); // 通过一个循环,不断监听,接收数据 while (true) { // 接收消息的实体 final byte[] buf = new byte[512]; DatagramPacket receivePack = new DatagramPacket(buf, buf.length); // 开始接收数据 datagramSocket.receive(receivePack); // 打印接收到的信息 String ip = receivePack.getAddress().getHostAddress(); int port = receivePack.getPort(); int dataLength = receivePack.getLength(); String data = new String(receivePack.getData(), 0, dataLength); System.out.println("UDPProvider receive form ip:" + ip + "\tport:" + port + "\tdata:" + data); // 获得目标端口 int responsePort = MessageCreator.parsePort(data); if (responsePort != -1){ // 构建一份回送数据 String responseData = MessageCreator.buildWithSN(sn); byte[] reponseDataBytes = responseData.getBytes(); // 直接根据发送者,构建回送数据实体 DatagramPacket responsePacket = new DatagramPacket(reponseDataBytes, reponseDataBytes.length, receivePack.getAddress(), // 采用指定的端口,而不是解析获得的来源端口(来源端口不一定就是监听端口,这是有些时候为了简化而已) responsePort); // 发送构建好的回送消息 datagramSocket.send(responsePacket); System.out.println("start send data."); } } }catch (Exception ignore){ }finally { close(); } // 发送结束 System.out.println("UDPProvider finished."); } /** * 对外提供结束方法 */ void exit(){ done = true; close(); } /** * 本地关闭DatagramSocket的方法 */ private void close(){ if (datagramSocket != null){ datagramSocket.close(); datagramSocket = null; } } } } NIO 介绍从BIO到Netty的演变 (6)
内容版权声明:除非注明,否则皆为本站原创文章。