Java Socket回声程序双向通信异常求助
Java Socket双向回声程序停滞的原因及解决方法
你的问题核心在于**InputStream.readAllBytes()的行为特性**:这个方法会持续从输入流读取数据,直到流的末尾(EOF,即对方关闭了输出流或整个Socket连接)才会返回。
双向通信时的死锁逻辑
- 服务器端启动后,阻塞在
serverSocket.accept(),客户端连接后,服务器执行in.readAllBytes()。此时客户端只是发送了消息并调用flush(),但客户端的输出流并没有关闭(因为客户端还要读取服务器的响应),所以服务器的输入流不会触发EOF,服务器会一直卡在readAllBytes()这一步,无法执行后续的回写操作。 - 客户端发送完消息后,执行
in.readAllBytes(),此时服务器还没处理完消息(卡在读取步骤),根本没有回传数据,客户端也会阻塞在这个读取操作上。 - 双方互相等待对方的操作完成,最终形成死锁,程序停滞。
单向通信正常的原因
单向通信场景下,客户端发送完消息后,try-with-resources会自动关闭Socket连接(包括输出流),此时服务器的输入流触发EOF,readAllBytes()就能读取到所有发送的数据并返回,所以流程能正常走完。
修复方案
不要依赖readAllBytes()这种需要触发EOF才能返回的方法,改用明确的消息边界处理方式,比如以下两种常见方案:
方案1:先发送消息长度,再发送内容
通过先告知对方要接收的字节数,避免依赖EOF判断:
package org.example; import java.io.*; import java.net.*; public class Main { public static void main(String[] args) { new Thread(() -> { try (ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept(); DataInputStream in = new DataInputStream(socket.getInputStream()); DataOutputStream out = new DataOutputStream(socket.getOutputStream())) { System.out.println("SERVER: reading message length..."); int length = in.readInt(); byte[] bytes = new byte[length]; in.readFully(bytes); System.out.println("SERVER: message from the client: " + new String(bytes)); System.out.println("SERVER: sending message back..."); out.writeInt(length); out.write(bytes); out.flush(); System.out.println("SERVER: message sent back."); } catch (Exception e) { e.printStackTrace(); } }).start(); new Thread(() -> { try (Socket socket = new Socket("localhost", 8080); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); DataInputStream in = new DataInputStream(socket.getInputStream())) { String msg = "hello world"; byte[] bytes = msg.getBytes(); System.out.println("CLIENT: sending message..."); out.writeInt(bytes.length); out.write(bytes); out.flush(); System.out.println("CLIENT: message sent."); System.out.println("CLIENT: reading response from the server..."); int length = in.readInt(); byte[] respBytes = new byte[length]; in.readFully(respBytes); System.out.println("CLIENT: response from the server: " + new String(respBytes)); } catch (Exception e) { e.printStackTrace(); } }).start(); } }
方案2:使用行分隔符作为消息边界(适合文本消息)
用BufferedReader.readLine()和PrintWriter.println(),通过换行符来标识单条消息的结束:
package org.example; import java.io.*; import java.net.*; public class Main { public static void main(String[] args) { new Thread(() -> { try (ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { System.out.println("SERVER: reading message..."); String msg = in.readLine(); System.out.println("SERVER: message from the client: " + msg); System.out.println("SERVER: sending message back..."); out.println(msg); System.out.println("SERVER: message sent back."); } catch (Exception e) { e.printStackTrace(); } }).start(); new Thread(() -> { try (Socket socket = new Socket("localhost", 8080); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { String msg = "hello world"; System.out.println("CLIENT: sending message..."); out.println(msg); System.out.println("CLIENT: message sent."); System.out.println("CLIENT: reading response from the server..."); String resp = in.readLine(); System.out.println("CLIENT: response from the server: " + resp); } catch (Exception e) { e.printStackTrace(); } }).start(); } }
内容的提问来源于stack exchange,提问作者JackStar
相关产品推荐
相关产品推荐

