You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让同端口的TCP进程通知UDP进程?

实现方案

由于TCPMain和UDPMain运行在同一个JVM进程中(TCPMain直接调用UDPMain的main方法),不需要跨进程通信,直接通过进程内的线程安全通信机制即可实现需求。以下是具体实现步骤和代码示例:

核心思路

  1. 重构UDP逻辑为可实例化的类,封装监听、发送功能,并提供供TCP调用的通知入口。
  2. TCP启动时保存UDP实例的引用,当收到特定消息时,调用UDP实例的通知方法触发发送动作。
  3. 使用线程安全的阻塞队列作为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:37:02