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

TCP服务器二次发送对象触发StreamCorruptedException问题求助

问题分析与解决

问题现象

TCP服务器首次向客户端发送随机对象时一切正常,但再次发送时触发错误:java.io.StreamCorruptedException: invalid stream header: 73720019,调用flush()方法无效。

服务器端代码

try {
    serverSocket = new ServerSocket(PORT);
    textArea.append("Server started, port : " + PORT + "\n");
    socket = serverSocket.accept();
    textArea.append("Client connected...\n");

    Object object = randomObject();
    out = new ObjectOutputStream(socket.getOutputStream());
    out.writeObject(object);
    textArea.append("Object sent...\n");
    String message = "";

    while(socket.isConnected()){
        in = new ObjectInputStream(socket.getInputStream());
        message = String.valueOf(in.readObject());
        if(message.equals("Please, send me object again...")){
            textArea.append("Message received : " + message + "\n");
            Object s = randomObject();
            out.writeObject(s);
            textArea.append("Object sent again...\n");
        }
    }

} catch (IOException e) {
    throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

客户端代码(报错行在new ObjectInputStream处)

try {
    socket = new Socket(ADDRESS, PORT);
    System.out.println("Connected...");

    speedLbl.setText("Speed : " + speed + "px");

    while(socket.isConnected()){
        inputStream = socket.getInputStream();

        in = new ObjectInputStream(inputStream);
        object = in.readObject();

        if(object instanceof Kvadrat){
            kvadrat = (Kvadrat) object;
            koordinatniSistem.add(kvadrat);
            System.out.println(kvadrat.getName());
            label.setText("X : " + kvadrat.getX() + " - Y: " + kvadrat.getY());
        } else if (object instanceof Pravougaonik) {
            pravougaonik = (Pravougaonik) object;
            koordinatniSistem.add(pravougaonik);
            System.out.println(pravougaonik.getName());
            label.setText("X : " + pravougaonik.getX() + " - Y: " + pravougaonik.getY());
        } else if (object instanceof Krug) {
            krug = (Krug) object;
            koordinatniSistem.add(krug);
            System.out.println(krug.getName());
            label.setText("X : " + krug.getX() + " - Y: " + krug.getY());
        }else if (object instanceof Trougao) {
            trougao = (Trougao) object;
            koordinatniSistem.add(trougao);
            System.out.println(trougao.getName());
            label.setText("X : " + trougao.getX() + " - Y: " + trougao.getY());
        } else {
            System.out.println(object.getClass().getSimpleName());
        }
        koordinatniSistem.repaint();
    }

} catch (IOException | ClassNotFoundException e) {
    throw new RuntimeException(e);
}

问题根源

  1. 服务器端错误:在循环内重复创建ObjectInputStream。ObjectInputStream初始化时会读取并解析流的头部信息,第一次创建后头部已被消耗,后续创建时会读取到对象数据而非头部,导致流结构破坏。
  2. 客户端错误:同样在循环内重复创建ObjectInputStream。首次创建后,流中剩余的是对象数据,再次创建时会尝试读取新的流头部,实际读到的是对象的序列化数据(73720019是序列化对象的标识开头),直接触发StreamCorruptedException。

修复方案

服务器端修改

将ObjectInputStream的创建移到循环外部,仅初始化一次:

try {
    serverSocket = new ServerSocket(PORT);
    textArea.append("Server started, port : " + PORT + "\n");
    socket = serverSocket.accept();
    textArea.append("Client connected...\n");

    Object object = randomObject();
    out = new ObjectOutputStream(socket.getOutputStream());
    // 移到循环外,只创建一次输入流
    in = new ObjectInputStream(socket.getInputStream());
    out.writeObject(object);
    textArea.append("Object sent...\n");
    String message = "";

    while(socket.isConnected()){
        message = String.valueOf(in.readObject());
        if(message.equals("Please, send me object again...")){
            textArea.append("Message received : " + message + "\n");
            Object s = randomObject();
            out.writeObject(s);
            out.flush(); // 可选,确保数据立即发送
            textArea.append("Object sent again...\n");
        }
    }

} catch (IOException e) {
    throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

客户端修改

将ObjectInputStream的创建移到循环外部,仅初始化一次:

try {
    socket = new Socket(ADDRESS, PORT);
    System.out.println("Connected...");

    speedLbl.setText("Speed : " + speed + "px");
    // 移到循环外,只创建一次输入流
    inputStream = socket.getInputStream();
    in = new ObjectInputStream(inputStream);

    while(socket.isConnected()){
        object = in.readObject();

        if(object instanceof Kvadrat){
            kvadrat = (Kvadrat) object;
            koordinatniSistem.add(kvadrat);
            System.out.println(kvadrat.getName());
            label.setText("X : " + kvadrat.getX() + " - Y: " + kvadrat.getY());
        } else if (object instanceof Pravougaonik) {
            pravougaonik = (Pravougaonik) object;
            koordinatniSistem.add(pravougaonik);
            System.out.println(pravougaonik.getName());
            label.setText("X : " + pravougaonik.getX() + " - Y: " + pravougaonik.getY());
        } else if (object instanceof Krug) {
            krug = (Krug) object;
            koordinatniSistem.add(krug);
            System.out.println(krug.getName());
            label.setText("X : " + krug.getX() + " - Y: " + krug.getY());
        }else if (object instanceof Trougao) {
            trougao = (Trougao) object;
            koordinatniSistem.add(trougao);
            System.out.println(trougao.getName());
            label.setText("X : " + trougao.getX() + " - Y: " + trougao.getY());
        } else {
            System.out.println(object.getClass().getSimpleName());
        }
        koordinatniSistem.repaint();
    }

} catch (IOException | ClassNotFoundException e) {
    throw new RuntimeException(e);
}

关键说明

  • ObjectInputStream和ObjectOutputStream是状态化的流处理类,它们会维护流的上下文(如对象引用缓存、头部信息等),必须在整个连接生命周期内仅初始化一次。
  • 发送对象后调用flush()可以确保数据立即写入底层Socket流,避免数据滞留,但这不是本次问题的根源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:42:32