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

Java Socket读取JSON对象无异常无预期输出问题求解

问题根因
  • 读消息的循环终止条件错误:BufferedReader.readLine()仅在对端关闭连接、输入流到达末尾时才会返回null。常规C/S长连接场景下,Socket不会在发送完单条消息后主动断开,你的代码会一直阻塞在while循环中等待流结束,永远不会执行后续的JSON解析、字段打印逻辑,这就是无异常也无输出的核心原因。
  • 未定义明确的消息边界:发送端直接将JSON序列化后的字符串写入输出流,没有添加任何分隔标识,即使修正循环逻辑,TCP传输的粘包/拆包问题会导致多条JSON拼接、单条JSON被拆分的情况,直接触发JSON解析失败。
  • 额外的坏实践:每次发送消息都新建PrintWriter包装流,既会产生不必要的性能开销,反复创建包装流还可能导致缓冲区数据异常。
修复方案

核心思路是用换行符作为单条JSON消息的边界(常规JSONObject.toString()输出的压缩格式JSON本身不含换行符,不会和边界标记冲突),发送端每条JSON末尾输出换行,接收端每读到一行完整内容就直接解析,不需要等流结束。

修正后的发送端代码

连接建立时初始化一次输出流,整个连接生命周期复用,不要每次发消息都新建:

// 连接初始化时创建输出流,全局复用
private PrintWriter printWriter;

public void initStream() throws IOException {
    // 显式指定UTF-8编码,避免不同系统默认编码不一致导致乱码
    printWriter = new PrintWriter(
            new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)
    );
}

public void writeMessage(JSONObject json) {
    // 用println输出,自动在JSON末尾添加换行符作为消息边界
    printWriter.println(json.toString());
    printWriter.flush();
}

修正后的接收端代码

每读到一行内容就直接解析为JSON,不需要循环拼接所有读到的内容:

private static void readMessageFromServer(Socket socket) {
    // 同样显式指定UTF-8编码,和发送端保持一致
    try (BufferedReader br = new BufferedReader(
            new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)
    )) {
        String readLine;
        // 读到一行就处理一行,每行对应一个完整JSON
        while ((readLine = br.readLine()) != null) {
            // 跳过传输中可能产生的空行
            if (readLine.isBlank()) continue;
            JSONObject js = new JSONObject(readLine);
            // 直接用JSONObject提供的getString方法取值,比手动强转更安全
            String action1 = js.getString("action1");
            System.out.println(action1);
        }
    } catch (IOException e) {
        System.out.println("连接异常:" + e.getMessage());
    }
}
扩展注意事项
  • 上述换行分隔的方案仅适用于传输压缩格式、无内部换行的JSON。如果需要传输格式化后带换行的JSON内容,请改用「长度前缀+内容」的自定义协议:先发送4字节整数标记后续JSON内容的字节长度,再发送对应长度的JSON字节;接收端先读取长度值,再读取满对应长度的字节后解析,从根本上避免粘包问题。
  • 所有IO流的包装器(PrintWriter、BufferedReader等)都要在Socket连接建立时初始化一次复用,不要每次读写都新建。
  • 收发两端必须显式指定相同的字符集,禁止依赖操作系统默认编码,否则跨环境运行时大概率出现乱码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:45:37