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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:41:01