如何从Java Server Socket向浏览器发送文件?连接重置问题解决
问题排查与修复方案
针对你发送视频、PDF等文件时连接重置的问题,从代码里能定位到几个核心问题,逐个解决即可:
1. 文件长度int溢出问题
file.length()返回的是long类型,当文件超过2GB时,强制转int会直接溢出,导致Content-Length头的值完全错误。客户端接收时发现实际数据长度和响应头声明的不匹配,就会直接重置连接。解决方法是把长度变量改成long类型:
long size = file.length();
同时Content-Length的取值也要用这个long变量。
2. 处理HTTP持久连接
HTTP/1.1默认开启持久连接(Keep-Alive),如果你的服务器没有后续响应返回,客户端会一直等待,超时后就会触发连接重置。可以在响应头里明确关闭连接:
responseStr += "Connection: close\r\n";
3. 用try-with-resources安全管理流
原代码直接调用fis.close(),如果中间写入过程抛出异常,流可能无法被正确关闭,进而导致资源泄漏和连接异常。用Java 7+的try-with-resources可以自动关闭流,避免这类问题。
4. 修正Content-Type设置
application/force-download虽然能触发下载,但对于视频、PDF这类文件,应该使用正确的MIME类型(比如视频用video/mp4,PDF用application/pdf),否则客户端可能无法正确解析文件,引发异常。如果不确定MIME类型,可以用Files.probeContentType()自动探测:
String mimeType = Files.probeContentType(file.toPath()); if (mimeType == null) { mimeType = "application/octet-stream"; // 兜底的二进制类型 } responseStr += "Content-Type: " + mimeType + "\r\n";
修复后的完整代码
void binaryResponse(OutputStream clientOutput, File file) throws IOException { long size = file.length(); String mimeType = Files.probeContentType(file.toPath()); if (mimeType == null) { mimeType = "application/octet-stream"; } String responseStr = "HTTP/1.1 200 OK\r\n"; responseStr += "Content-Type: " + mimeType + "\r\n"; responseStr += "Content-Length: " + size + "\r\n"; responseStr += "Connection: close\r\n\r\n"; // 指定UTF-8编码写入响应头,避免环境编码差异导致乱码 clientOutput.write(responseStr.getBytes(StandardCharsets.UTF_8)); // try-with-resources自动关闭输入流 try (FileInputStream fis = new FileInputStream(file)) { byte[] buffer = new byte[4 * 1024]; long remaining = size; int bytesRead; while (remaining > 0 && (bytesRead = fis.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { clientOutput.write(buffer, 0, bytesRead); remaining -= bytesRead; // 大文件传输时定期flush,避免缓冲区积压 clientOutput.flush(); } } clientOutput.flush(); }
额外注意点:
- 写入响应头时指定UTF-8编码,避免不同系统环境下的编码混乱
- 大文件传输过程中定期flush输出流,防止缓冲区溢出
- 检查Ubuntu系统的网络限制(比如文件描述符数量、TCP超时设置),避免系统层面强制断开连接
内容的提问来源于stack exchange,提问作者MD. MEHEDI IMAM
相关产品推荐
相关产品推荐

