如何让同端口的TCP进程通知UDP进程?
实现方案
由于TCPMain和UDPMain运行在同一个JVM进程中(TCPMain直接调用UDPMain的main方法),不需要跨进程通信,直接通过进程内的线程安全通信机制即可实现需求。以下是具体实现步骤和代码示例:
核心思路
- 重构UDP逻辑为可实例化的类,封装监听、发送功能,并提供供TCP调用的通知入口。
- TCP启动时保存UDP实例的引用,当收到特定消息时,调用UDP实例的通知方法触发发送动作。
- 使用线程安全的阻塞队列作为TCP与UDP的消息传递通道,避免手动锁的复杂操作。
代码实现
1. 重构UDP服务类(UDPServer)
将UDP的监听、发送逻辑封装成可控制的类,暴露通知方法:
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class UDPServer { private final int port; private final BlockingQueue<String> sendQueue = new LinkedBlockingQueue<>(); private DatagramSocket socket; private boolean running = true; // 记录UDP客户端的地址与端口(UDP无连接,需通过接收数据包获取) private InetAddress clientAddr; private int clientPort; public UDPServer(int port) { this.port = port; } public void start() { new Thread(() -> { try { socket = new DatagramSocket(port); byte[] buffer = new byte[1024]; System.out.println("UDP服务启动,监听端口: " + port); while (running) { // 处理UDP接收逻辑 DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length); socket.receive(receivePacket); // 更新客户端地址(后续发送用) clientAddr = receivePacket.getAddress(); clientPort = receivePacket.getPort(); String receivedMsg = new String(receivePacket.getData(), 0, receivePacket.getLength()); System.out.println("UDP收到消息: " + receivedMsg); // 检查是否有需要发送的消息 String msgToSend = sendQueue.poll(); if (msgToSend != null && clientAddr != null) { sendUDPMessage(msgToSend); } } } catch (Exception e) { e.printStackTrace(); } finally { if (socket != null && !socket.isClosed()) socket.close(); } }).start(); } // 发送UDP数据包到客户端 private void sendUDPMessage(String message) { try { byte[] data = message.getBytes(); DatagramPacket sendPacket = new DatagramPacket(data, data.length, clientAddr, clientPort); socket.send(sendPacket); System.out.println("UDP已发送通知: " + message); } catch (Exception e) { e.printStackTrace(); } } // 供TCP调用的通知方法,将消息加入发送队列 public void notifyToSend(String message) { try { sendQueue.put(message); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } public void stop() { running = false; if (socket != null && !socket.isClosed()) socket.close(); } }
2. 修改UDPMain类
让UDPMain负责启动UDP服务并返回实例引用:
public class UDPMain { // 对外暴露启动方法,返回UDPServer实例 public static UDPServer startUDPServer(int port) { UDPServer server = new UDPServer(port); server.start(); return server; } public static void main(String[] args) { int port = args.length > 0 ? Integer.parseInt(args[0]) : 8888; startUDPServer(port); } }
3. 修改TCPMain类
启动UDP服务并保存引用,收到特定消息时触发UDP发送:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class TCPMain { private static UDPServer udpServer; public static void main(String[] args) { // 启动UDP服务并保存实例 int port = args.length > 0 ? Integer.parseInt(args[0]) : 8888; udpServer = UDPMain.startUDPServer(port); // 启动TCP服务 startTCPServer(port); } private static void startTCPServer(int port) { new Thread(() -> { try (ServerSocket serverSocket = new ServerSocket(port)) { System.out.println("TCP服务启动,监听端口: " + port); while (true) { Socket clientSocket = serverSocket.accept(); // 为每个TCP客户端启动独立线程处理 new Thread(() -> handleTCPClient(clientSocket)).start(); } } catch (Exception e) { e.printStackTrace(); } }).start(); } private static void handleTCPClient(Socket clientSocket) { try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) { String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("TCP收到消息: " + inputLine); // 判断是否为触发UDP发送的特定消息 if ("TRIGGER_UDP_SEND".equals(inputLine)) { // 通知UDP发送自定义内容 udpServer.notifyToSend("来自TCP的触发通知"); } // 其他TCP消息处理逻辑... } } catch (Exception e) { e.printStackTrace(); } finally { try { clientSocket.close(); } catch (Exception e) { e.printStackTrace(); } } } }
关键说明
- 端口兼容性:TCP和UDP可以同时监听同一个端口,操作系统会根据协议类型区分请求,不会出现端口冲突。
- 线程安全:使用
LinkedBlockingQueue作为消息通道,天然支持多线程安全访问,无需手动加锁。 - UDP客户端地址:UDP是无连接协议,需通过接收客户端的数据包获取其地址,代码中记录了最近一次通信的客户端地址,若需支持多客户端,可维护客户端地址列表。
内容的提问来源于stack exchange,提问作者hide on bush
相关产品推荐
相关产品推荐

