套接字关闭问题 - 最后一部分数据丢失

时间:2009-12-16 01:16:01

标签: java http sockets

我有一个Java程序接受连接,接收HTTP请求并发送HTTP回复和存储在文件中的一些数据(这是缓存代理的一部分)。删除所有不相关的内容,我的代码如下所示:

FileInputStream fileInputStream = new FileInputStream(file);
OutputStream outputStream = socket.getOutputStream();
byte[] buf = new byte[BUFFER_SIZE];
int len = 0;
while ((len = fileInputStream.read(buf)) > 0) {
    outputStream.write(buf, 0, len);
}
outputStream.flush();
socket.close();

此代码在每个连接的客户端的特定线程中执行。

当我处理小文件(.htm,.gif,.swf等)时,一切正常(但是,我没有看到浏览器中的任何错误)。但是当我下载大文件(.iso),特别是同时下载几个文件时,当系统处于负载状态时,有时我会遇到很奇怪的行为。浏览器下载99.99%的文件,当缺少BUFFER_SIZE的未下载字节时,下载停止几秒钟,然后浏览器说出现错误。我无法理解会发生什么,因为所有数据都已成功读取,甚至所有数据也成功写入outputStream。正如你所看到的,我甚至做了flush(),但它没有结果。

任何人都能解释一下会发生什么吗?

修改
将项目上传到filehosting.org Download source files。有zip源存档,包含源代码,Build.xml和Readme.txt。使用ant构建解决方案。在ClientManager.java中发生了所描述的问题,您可以在那里找到评论。

4 个答案:

答案 0 :(得分:2)

基于JDK 1.6代码库的快速拖网:

  • socket.getOutputStream()返回SocketOutputStream个实例
  • flush()确实对SocketOutputStream实例
  • 没有影响 write()实例上的
  • SocketOutputStream似乎没有缓冲Java代码中的任何内容
  • shutdownOutput()应确保在关闭套接字的输出端之前写入任何未完成的数据。至少,评论说明了这一点。

然而,一些Socket等实现是本机方法,我没有深入研究。

根据我的判断,“正确”序列将是:

socket.shutdownOutput();
socket.close();

但是,你说你已经尝试过了。另一端的应用程序是否可能提前关闭TCP / IP连接?

另一个想法:你试过setSoLinger(true, 60000),但操作系统允许60000秒可能更长。尝试setSoLinger(true, 60),然后在打开输出流之前尝试执行此操作。

答案 1 :(得分:1)

不确定为什么会发生这种情况,我发现您的代码没有问题。您是否尝试使用BufferedInputStream括起FileInputStream

答案 2 :(得分:1)

我认为最可能的原因是您关闭了连接而没有等待数据完全传输。

您可以让Java等待一段时间,

socket.setOption(SocketOptions.SO_LINGER, new Integer(60));

答案 3 :(得分:0)

我习惯先发送长度,然后等到我获得数据,但如果你不能这样做,这篇博客应该会有所帮助:

http://vadmyst.blogspot.com/2008/04/proper-way-to-close-tcp-socket.html

这适用于.NET,但基本逻辑应该相同。

发送数据后,您需要让发送方关闭其连接,然后执行shutdownOutput并让对方继续阅读,直到出现无法读取任何内容的情况,或者抛出异常,然后你应该拥有一切。