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

Java Socket文件上传内容重复问题排查与解决求助

问题根源分析

你的代码采用先发送文件长度、再按长度传输内容的方案,本身不需要依赖EOF判断传输结束,但出现文件内容重复的问题,核心并非无法识别EOF,而是:

  • 调试代码误导:客户端和服务端都遍历整个1024字节的buffer打印,包括未被实际读取/接收填充的旧数据(比如最后一次传输时,bytes小于1024,buffer剩余位置保留上一次传输的内容),导致你在控制台看到重复内容,误以为文件本身重复。
  • 冗余循环条件:同时判断size>0和bytes!=-1,逻辑冗余,极端场景下可能导致传输提前终止,但不会引发内容重复。

你提到的“无法识别EOF”是对问题的误判——这个方案里已经通过文件长度明确了终止条件,EOF本来就不需要被识别。

修复方案

1. 修正调试代码(解决控制台重复显示)

将遍历整个buffer的打印逻辑,改为只遍历实际读取/接收的bytes长度:

客户端sendFile方法的打印循环替换为:

// 只遍历已读取的有效字节
for (int j = 0; j < bytes; j++) {
    try {
        byte b = buffer[j];
        if ((char)b == '\n' || r == 0)
            System.out.print("\n" + (++r));
        System.out.print((char)b);
    } catch (Exception ex) {
        // 捕获非ASCII字节的字符转换异常
    }
}

服务端receiveFile方法的打印循环替换为:

// 只遍历已接收的有效字节
for (int j = 0; j < bytes; j++) {
    try {
        System.out.print((char)buffer[j]);
    } catch (Exception ex) {
    }
}

2. 简化循环条件(消除逻辑冗余)

因为已经通过size控制总传输字节数,bytes!=-1的判断多余,修改客户端和服务端的while循环:

客户端:

while (size > 0) {
    bytes = input.read(buffer, 0, (int) Math.min(buffer.length, size));
    if (bytes == -1) {
        System.err.println("文件读取提前结束");
        break;
    }
    // 写入Socket、更新size的逻辑不变
    out.write(buffer, 0, bytes);
    out.flush();
    size -= bytes;
}

服务端:

while (size > 0) {
    bytes = in.read(buffer, 0, (int) Math.min(buffer.length, size));
    if (bytes == -1) {
        System.err.println("客户端连接提前断开");
        break;
    }
    // 写入文件、更新size的逻辑不变
    output.write(buffer, 0, bytes);
    size -= bytes;
}

3. 优化Socket关闭顺序

客户端发送完文件后,先关闭输出流,明确告知服务端传输结束:

// 客户端构造方法里的关闭顺序
out.close(); // 先关输出流,发送EOF标记
in.close();
socket.close();
验证方法

修复后,对比原文件和上传后文件的MD5值确认内容一致;同时控制台打印内容会和原文件完全匹配,无重复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:40:30