我有一个Java applet,它使用HTTPURLConnection
类将非常大的文件上传到IIS-7 Web服务器。 applet将文件分块,然后使用固定长度的流式传输到PHP脚本。
有时,在上传文件块时,客户端和服务器之间的网络连接会神秘地丢失。发生这种情况时,我对writeBytes()
方法的调用会抛出IOException
,我会抓住它。在捕获此异常后,我会进入finally
块,在那里我尝试清理它。由于没有足够的数据写入连接(请记住,这是固定长度的流式传输),关闭输出流的尝试也会失败。结果,连接看起来“粘住”(即底层插座保持打开)。这似乎是通过查看StreamingOutputStream类的source code到close()
方法来验证的(注意说明无法关闭套接字的注释)。
在写出IOException
的同时,抓住HTTPURLConnection
之后我可以关闭一个优雅的方式吗?将HTTPURLConnection
对象告诉disconnect()
似乎不够好。
这是我通过调用writeBytes()
类的HTTPURLConnection
方法调用网络时看到的第一个异常:
java.io.IOException: Error writing request body to server
at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(Unknown Source)
at java.io.DataOutputStream.write(Unknown Source)
at MultiPartPostThread.run(MultiPartPostThread.java:321)
我捕获此异常,然后尝试关闭我用来写入连接的DataOutputStream
对象。当我这样做时,我得到了这个例外:
java.io.IOException: insufficient data written
at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.close(Unknown Source)
at java.io.FilterOutputStream.close(Unknown Source)
at MultiPartPostThread.run(MultiPartPostThread.java:370)
我可以通过注意在IIS日志中显示失败条目需要10分钟来验证套接字是否保持打开状态。延迟(10分钟)恰好是我的连接超时值。 IIS日志中的示例行(为简洁而修剪):
2012-01-31 20:20:07 POST /upload_handler.php 200 0 0 356 26215490 3666
2012-01-31 20:20:10 POST /upload_handler.php 200 0 0 356 26215490 3853
2012-01-31 20:30:22 POST /upload_handler.php 500 0 64 0 15286099 611442
请注意,在日志的前两行中我们正在很好地传输:每次发送25 MB,并返回200状态代码。然后失败然后在最后一次成功转移后10分钟出现,并且有一个无用的错误500(并注意这只是部分转移;仅转移了约15MB)。实际上,这个神秘的断开发生在整个过程大约1分钟,所以我在IIS跟踪日志中看到的超时消息是红色鲱鱼。我在PHP日志,HTTPERR日志或服务器上的系统日志中看不到任何帮助。
答案 0 :(得分:1)
在您的信息流上呼叫close()
应释放
HTTPURLConnection
这是来自HTTPURLConnection javadoc的注释
在请求之后调用HttpURLConnection的InputStream或OutputStream上的close()方法可以释放与此实例关联的网络资源,但不会影响任何共享持久连接。如果此时持久连接处于空闲状态,则调用disconnect()方法可能会关闭底层套接字。
答案 1 :(得分:1)
我越是关注这一点,我越相信不能进行优雅的清理。 disconnect()
调用似乎不足以关闭底层套接字;你只需等待它超时。
我想我会尝试使用Apache HttpComponents HttpClient(根据terrific SO wiki post底部的建议),看看它内置的错误处理是否可以解决这个奇怪的情况我是看到。