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

Java TCP Socket同机通信正常,局域网运行JAR包仅首条消息可达如何解决

根本原因
  1. 服务端接收逻辑设计错误
    available()方法仅返回当前操作系统套接字缓冲区中可无阻塞读取的字节数,不代表对端已发送的总数据量。网络传输存在延迟时,首条消息读取完成后,下一条消息还未到达本地缓冲区,available()会返回0,直接终止读取循环,后续消息永远不会被读取。同时你用主线程统一读取所有客户端Socket,只要一个Socket读操作阻塞就会卡住所有客户端的消息处理。
  2. 客户端套接字非优雅关闭
    客户端单次发送逻辑执行完成后没有保持进程运行,也没有执行套接字关闭流程,直接退出进程时操作系统会发送RST包强制断开连接,而非正常的FIN四次挥手,属于非优雅关闭。此时服务端还在等待读取数据就会触发Connection reset异常。IntelliJ IDEA运行时正常是因为IDE对启动的进程默认添加了套接字回收延迟机制,Eclipse和直接运行JAR包没有该机制,所以会暴露问题。

解决方案

服务端修改

  1. 废弃available()作为循环判断条件,改用阻塞读模式,且每个客户端连接分配独立的读取线程,避免互相影响。示例代码如下:
// 每个客户端连接对应独立线程的读取逻辑
DataInputStream dIn = new DataInputStream(client.getInputStream());
try {
    while (true) {
        // 阻塞读类型字段,读到EOFException说明客户端正常断开连接
        byte type = dIn.readByte();
        switch(type) {
            case 0:
                System.out.println(dIn.readUTF());
                break;
            case 1:
                System.out.println(dIn.readInt());
                break;
            case 2:
                System.out.println(dIn.readByte());
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + type);
        }
    }
} catch (EOFException e) {
    // 客户端正常断开,清理资源
    System.out.println("客户端正常断开连接");
} catch (SocketException e) {
    if ("Connection reset".equals(e.getMessage())) {
        // 客户端异常断开,清理对应Socket资源即可
        System.out.println("客户端异常断开连接");
    }
} finally {
    dIn.close();
    client.close();
    // 从Socket列表中移除当前连接
}
  1. 移除主线程统一读取所有客户端的逻辑,接入连接时直接启动独立线程处理该客户端的读写。

客户端修改

  1. 若需要持续发送消息,将发送逻辑放入循环保持进程运行,不要单次发送后直接结束进程,比如可以监听控制台输入触发消息发送。
  2. 若需要结束通信,执行优雅关闭流程:
// 告知服务端自身已无数据发送
clientSocket.shutdownOutput();
// 等待服务端返回确认后再关闭资源
dOut.close();
dIn.close();
clientSocket.close();

内容的提问来源于stack exchange,提问作者Dubstepzedd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:27:02