我有一个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中发生了所描述的问题,您可以在那里找到评论。
答案 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
并让对方继续阅读,直到出现无法读取任何内容的情况,或者抛出异常,然后你应该拥有一切。