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); }
问题根源
- 服务器端错误:在循环内重复创建
ObjectInputStream。ObjectInputStream初始化时会读取并解析流的头部信息,第一次创建后头部已被消耗,后续创建时会读取到对象数据而非头部,导致流结构破坏。 - 客户端错误:同样在循环内重复创建
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
相关产品推荐
相关产品推荐

