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

Java Socket客户端与服务器无法连接:new ObjectInputStream阻塞问题

问题分析与解决

客户端执行objectInputStream = new ObjectInputStream(socket.getInputStream());时持续阻塞,服务器可识别连接但无法完成双向流初始化,核心问题及解决方法如下:

根本原因

ObjectInputStream的构造函数会主动读取对方ObjectOutputStream写入的序列化协议头部(魔数+版本号)。当前服务器端仅创建自身的ObjectInputStream,未先初始化ObjectOutputStream并发送头部数据,导致客户端输入流一直等待该数据,陷入阻塞。

解决方案

  1. 服务器端优先创建ObjectOutputStream并flush:在客户端输入流初始化前,服务器需先完成输出流的创建与刷新,确保序列化头部发送至客户端。
  2. Message类必须实现Serializable接口:这是对象序列化传输的强制要求,否则会触发序列化异常。

修正后的关键代码

服务器端ChatServerConnector类修正

class ChatServerConnector extends Thread {
    private ChatServer server;
    private Socket socket;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    private Message message;

    public ChatServerConnector(ChatServer server, Socket socket) {
        this.server = server;
        this.socket = socket;
    }

    public void run() {
        try {
            // 先创建输出流并刷新,发送序列化头部
            objectOutputStream = new ObjectOutputStream(this.socket.getOutputStream());
            objectOutputStream.flush();
            // 再创建输入流
            objectInputStream = new ObjectInputStream(this.socket.getInputStream());
            System.out.println("[system] connected with " + this.socket.getInetAddress().getHostName() + ":" + this.socket.getPort());
        } catch (IOException e) {
            System.err.println("[system] could not open streams!");
            e.printStackTrace();
            return;
        }

        while (true) {
            try {
                message = (Message)objectInputStream.readObject();
            } catch (Exception e) {
                System.err.println("[system] failed to read message");
                e.printStackTrace();
                break;
            }

            switch(message.type) {
                case "public":
                    try {
                        this.server.sendToAllClients(message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    // 处理其他类型消息
                    break;
            }
        }
        // 资源清理
        try {
            objectInputStream.close();
            objectOutputStream.close();
            socket.close();
            server.removeClient(socket);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Message类补充Serializable接口

import java.io.Serializable;

class Message implements Serializable {
    private static final long serialVersionUID = 1L; // 显式声明序列化版本号避免兼容性问题
    public String type;
    public String sender;
    public String reciever;
    public long time;
    public String message;
    // 构造函数、getter/setter等逻辑
}

额外注意事项

  • 客户端代码中sendMessage方法调用的tmp变量未定义,需补充终端输入读取逻辑,避免空指针异常。
  • 服务器端sendToAllClients方法需遍历客户端列表,为每个客户端复用或创建输出流发送消息,注意线程同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 23:03:11