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

Java Socket通信阻塞问题:客户端发送后服务端未接收

问题原因与解决办法

你的程序出现双向阻塞的核心问题是数据传输格式不匹配,同时存在两处逻辑错误,具体分析和修复方案如下:

一、核心问题分析

1. 客户端发送与服务端接收的格式不兼容

客户端用DataOutputStream.writeChars()发送字符串:

  • 该方法会把每个字符按UTF-16编码(每个字符占2字节)输出,且不会添加换行符;
    而服务端用BufferedReader.readLine()接收:
  • 该方法会一直阻塞,直到读取到换行符(\n或\r\n),同时它是按系统默认编码将字节转成字符串的。
    两者编码规则和终止符要求完全不匹配,服务端永远等不到换行符,陷入阻塞。

2. 客户端接收与服务端发送的格式也不兼容

客户端用DataInputStream.readUTF()接收:

  • 该方法要求数据必须是DataOutputStream.writeUTF()写入的格式(先写2字节的长度标识,再写UTF-8编码的字节);
    而服务端用PrintStream.println()发送的是普通字符串加换行符,不符合readUTF的读取规范,客户端同样会阻塞。

3. 服务端循环逻辑错误

  • 循环条件received != "Exit" || received != "exit"逻辑永远为true:无论received是什么值,总有一个条件成立,循环无法终止;
  • 字符串比较用!=是错误的:Java中!=比较的是对象地址,应该用!equals()或!equalsIgnoreCase()比较内容。

二、修复后的代码示例

推荐统一使用字符流传输文本,逻辑更清晰,避免编码格式冲突:

修复后的客户端代码

public void Client(int port, String ip) {
    try {
        sock = new Socket(ip, port);
        System.out.println("Found the server.");
        
        // 统一用字符流接收服务端数据
        BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        // 用PrintWriter发送数据,开启自动刷新缓冲区
        PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
        
        // 发送字符串并自动添加换行符,匹配服务端readLine()规则
        writer.println("Client Begining Conversation");
        // 读取服务端返回的一行数据
        System.out.println(reader.readLine());
        
        // 手动关闭资源(实际项目推荐用try-with-resources自动关闭)
        reader.close();
        writer.close();
        sock.close();
    } catch (UnknownHostException u) {
        System.out.println(u);
    } catch (IOException i) {
        System.out.println(i);
    }
}

修复后的服务端代码

public Server(int port) throws Exception {
    ServerSocket gameServer = new ServerSocket(port);
    Socket gameSocket = gameServer.accept();
    System.out.println("Client has connected");

    BufferedReader reader = new BufferedReader(new InputStreamReader(gameSocket.getInputStream()));
    PrintWriter writer = new PrintWriter(gameSocket.getOutputStream(), true);

    Play(reader, writer);
    
    // 关闭资源
    reader.close();
    writer.close();
    gameSocket.close();
    gameServer.close();
}

public void Play(BufferedReader reader, PrintWriter writer) throws Exception {
    String received, textSent;
    System.out.println("Waiting for response.");
    received = reader.readLine();
    System.out.println("Client has responded");
    
    // 修正循环条件:用equalsIgnoreCase忽略大小写,逻辑改为&&
    while (received != null && !"exit".equalsIgnoreCase(received)) {
        System.out.println(received);
        textSent = received + " received";
        // 发送数据并自动添加换行符
        writer.println(textSent);
        // 读取下一行数据,避免死循环
        received = reader.readLine();
    }
}

三、关键修复点说明

  1. 统一使用BufferedReader和PrintWriter:基于字符流传输文本,编码规则一致,println()自动添加换行符,完美匹配readLine()的读取逻辑;
  2. 修正服务端循环条件:用equalsIgnoreCase()忽略大小写判断退出指令,同时每次循环结束重新读取下一行数据,避免死循环;
  3. 补充资源关闭逻辑:避免Socket资源泄漏(生产环境推荐使用try-with-resources语法自动管理资源)。

内容的提问来源于stack exchange,提问作者Nehemiah Newell

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 12:15:33