文章目录
I UDP 交互原理
II UDP 服务器端代码示例
III UDP 客户端代码示例
IV 服务器 客户端 运行结果
I UDP 交互原理
1. UDP 单播传输流程 : A 给 B 发送数据包 , B 设备一定要处于监听 X 端口状态 , A 向 B 的 X 端口发送数据包 , B 才能收到 ; B 收到 A 的数据包后 , B 就知道了 A 的端口号 Z 的信息了 , 此时 B 可以向 A 的 Z 端口号发送数据包 ;
2. 局域网设备交互 : A 设备给局域网其它设备发送信息 , 并能接收到其它设备回送给 A 的信息 ;
3. 接收信息设备监听 X 端口 : 此时 A 作为客户端时 , 服务器需要接收 A 发送的数据包 , 服务器需要监听一个指定的接口 X , 那么如果 A 发送广播消息 , 监听 X 端口的服务器就会收到 A 发送的消息 ;
4. A 提前监听端口 Z : 如果服务器在收到消息后立刻向 A 的 Z 端口回送一个反馈信息 , 设备 A 需要在发送消息之前就监听 Z 端口 , 才能实现上述功能 ;
5. 持续交互 : A 不断向其它设备的 X 端口发送信息 , 其它设备可以不断反馈信息给设备 A 的 Z 端口 , 这样就实现了客户端与服务器端数据交互的功能 ;
II UDP 服务器端代码示例
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.util.ArrayList; public class UDPServer { public static void main(String[] args){ System.out.println("服务器 开始运行"); //开启接收数据的线程 ReceiveThread receiveThread = new ReceiveThread(); receiveThread.start(); } /** * 服务器端监听客户端发送的信息 */ private static class ReceiveThread extends Thread{ /** * 是否继续监听 , 循环控制变量 */ boolean isReceive = true; /** * 存储发送数据的客户端信息 */ ArrayList<Client> clients = new ArrayList<>(); @Override public void run() { super.run(); try { //I. 创建 DatagramSocket 对象 , 用于 UDP 数据包的发送和接收 //1. UDP 数据包接收者 , 监听 8888 端口 // 该 DatagramSocket 既可以接收数据包 , 也可以发送数据包 DatagramSocket datagramSocket = new DatagramSocket(8888); //II. 接收 UDP 数据包 , 无限循环接收来自客户端的信息 , 并根据不同的信息进行不同处理 while (isReceive){ //2. 接收数据包使用的缓冲区 byte[] receiveBuffer = new byte[256]; //3. 接收 UDP 数据包使用的 DatagramPacket 对象 DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length); //4. 接收 UDP 数据包 datagramSocket.receive(receivePacket); //5. 获取发送端的 IP 地址 String sendIP = receivePacket.getAddress().getHostAddress(); //6. 获取发送端的端口号 int sendPort = receivePacket.getPort(); //7. 获取接收到的数据的长度 int receiveLen = receivePacket.getLength(); //8. 获取接收到的数据 , 并转为字符串 String receiveData = new String(receivePacket.getData(), 0, receiveLen); //9. 打印接收到的数据包信息 System.out.println("服务器 接收到 " + sendIP + " : " + sendPort + " 发送的数据 : " + receiveData); //将客户端信息发送到 //III. 发送 UDP 数据包 //10. 将接收到的数据长度回送给发送者 String response = "服务器端 收到客户端发送的 " + receiveLen + " Byte 数据"; //11. 将字符串转为 byte[] 数组 byte[] responseData = response.getBytes(); //12. 创建发送数据包 , 需要传入的参数 1> 数据 2> 数据长度 3> 接收者的地址 4> 接收者的端口号 DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length, receivePacket.getAddress(), receivePacket.getPort()); //13. 将数据包发送出去 datagramSocket.send(responsePacket); System.out.println("服务器 向客户端 " + sendIP + " : " + sendPort + " 发送的数据 : " + response); //退出服务器循环 if("exit".equals(receiveData)){ isReceive = false; } } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { System.out.println("服务器 运行结束"); } } } /** * 封装向服务器端发送数据的客户端信息 * 主要是保存客户端的 IP 地址和端口号 */ private static class Client{ String ClientIP; String ClientPort; public Client(String clientIP, String clientPort) { ClientIP = clientIP; ClientPort = clientPort; } } }
III UDP 客户端代码示例
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class UDPClient { public static void main(String[] args){ try { System.out.println("客户端 开始运行"); //I. 创建 DatagramSocket 对象 , 用于 UDP 数据包的发送和接收 //1. UDP 数据包套接字 , 客户端 , // 监听 8889 端口 , 发送和接收数据包都使用该端口 DatagramSocket datagramSocket = new DatagramSocket(8889); //II. 人机交互控制台阻塞获取用户输入 //1. 获取控制台输入流 InputStream is = System.in; //2. 该输入流会阻塞 , 等待用户控制台输入 BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 循环控制变量 , 循环发送和接收 UDP 数据包 boolean flag = true; while(flag){ //3. 阻塞命令行 , 等待用户输入一行数据, 并存入 string 对象中 String string = br.readLine(); //III. 向服务器发送 UDP 数据包 //1. 将字符串转为 byte[] 数组 byte[] sendData = string.getBytes(); //2. 创建发送数据包 , 需要传入的参数 1> 数据 2> 数据长度 3> 接收者的地址 4> 接收者的端口号 // 向服务器端发送数据 , 发送的端口是自动分配的 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getLocalHost(), 8888); //3. 将数据包发送出去 datagramSocket.send(sendPacket); System.out.println("客户端 向服务器 : " + InetAddress.getLocalHost() + " : " + 8888 + " 发送的数据 : " + string); //4. 退出 if("exit".equals(string)){ flag = false; } //IV. 接收服务器反馈的 UDP 数据包 //1. 接收数据包使用的缓冲区 byte[] receiveBuffer = new byte[1024]; //2. 接收 UDP 数据包使用的 DatagramPacket 对象 DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length); //3. 接收 UDP 数据包 datagramSocket.receive(receivePacket); //4. 获取发送端的 IP 地址 String sendIP = receivePacket.getAddress().getHostAddress(); //5. 获取发送端的端口号 int sendPort = receivePacket.getPort(); //6. 获取接收到的数据的长度 int receiveLen = receivePacket.getLength(); //7. 获取接收到的数据 , 并转为字符串 String receiveData = new String(receivePacket.getData(), 0, receiveLen); //8. 打印接收到的数据包信息 System.out.println("客户端 接收到服务器端反馈信息 : " + sendIP + " : " + sendPort + " 发送的数据 : " + receiveData); } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { System.out.println("客户端 运行结束"); } } }
IV 服务器 客户端 运行结果
先运行服务器端 , 再运行客户端 ;