Java 为什么com.sun.net.httpserver.httpserver挂起?

Java 为什么com.sun.net.httpserver.httpserver挂起?,java,https,freeze,Java,Https,Freeze,当我使用com.sun.net.httpserver.httpserver实现的简单HTTPS服务器被调用via(使用curl)时,它工作正常。但是,一旦我不使用代理,而是更改我的web表单,以便浏览器直接向服务器发送请求,服务器就会变得不稳定,有时会停止响应。然后,客户端将等待响应,直到超时。这个问题很难重现,有时会在系统运行数小时后发生。所有这些都是通过HTTPS在非标准端口(目前为8081)上实现的。我的服务器返回XML 服务器不再响应时我看到的堆栈跟踪(通过“kill-QUIT[pid]

当我使用
com.sun.net.httpserver.httpserver
实现的简单HTTPS服务器被调用via(使用curl)时,它工作正常。但是,一旦我不使用代理,而是更改我的web表单,以便浏览器直接向服务器发送请求,服务器就会变得不稳定,有时会停止响应。然后,客户端将等待响应,直到超时。这个问题很难重现,有时会在系统运行数小时后发生。所有这些都是通过HTTPS在非标准端口(目前为8081)上实现的。我的服务器返回XML

服务器不再响应时我看到的堆栈跟踪(通过“
kill-QUIT[pid]
”):

“线程2”优先级=10 tid=0x0000000017fc4800 nid=0x1c2b可运行
[0x00002ba5ec97c000]
java.lang.Thread.State:可运行
位于sun.nio.ch.FileDispatcherImpl.read0(本机方法)
位于sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
位于sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:218)
位于sun.nio.ch.IOUtil.read(IOUtil.java:191)
在sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:359)
-锁定(一个java.lang.Object)
位于sun.net.httpserver.SSLStreams$EngineWrapper.recvAndUnwrap(SSLStreams.java:334)
-锁定(一个java.lang.Object)
位于sun.net.httpserver.SSLStreams.recvData(SSLStreams.java:409)
位于sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:524)
位于sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:593)
位于sun.net.httpserver.Request.readLine(Request.java:84)
在sun.net.httpserver.Request.(Request.java:54)
位于sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:529)
位于sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:156)
位于sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:424)
位于sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:389)
运行(Thread.java:722)
我已经尝试的内容:发送
连接:关闭
http头-没有帮助。编写一个Java测试用例,使用多个线程并行地查询服务器,效果很好

所以问题是:浏览器与我的代理有什么不同,为什么这会使我的服务器进程挂起

来源:这里是

背景:我希望任何人都能够从他们的网页使用我的REST服务,而无需安装代理(需要绕过Javascript跨源策略)。为此,服务器发送一个
访问控制允许来源:
头。与Jetty或Tomcat Embedded相比,我使用Java提供的类的开销最小。

为什么代理和无代理的行为不同?
  • 更多没有代理的连接
  • 现实世界的浏览器用户可以做一些有趣的事情,比如启动一个请求,然后取消/返回按钮/新建请求
您需要设置套接字超时。不幸的是,API文档没有建议以编程方式实现这一点

但您可以通过JVM系统属性设置重新请求和响应超时:

设置以下系统属性:

sun.net.httpserver.clockTick
默认值=10000,即10秒

sun.net.httpserver.timerMillis
默认值=1000,即1秒

sun.net.httpserver.maxReqTime
默认值=-1,即永远

默认值>0表示超时=默认值*(时钟信号或timerMillis)秒

sun.net.httpserver.maxrptime
默认值=-1,即永远

默认值>0表示超时=默认值*(时钟信号或timerMillis)秒


显然,在HttpHandler.handle()方法中,请确保在响应头中设置响应代码:

  httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length());  
  final OutputStream os = httpExchange.getResponseBody();  
  os.write( response.getBytes() );  
  os.close(); 

您在服务器端使用哪种类型/版本的OS和JVM?Ubuntu 10.04.4 LTS,Java是1.7.0_07-Java HotSpot(TM)64位服务器VMSome代码。没有它就无法真正诊断。:^)@我已经添加了源代码的链接。谢谢。此后,我仔细研究了API,发现默认情况下,服务器套接字请求和响应(在ServerConfig类中设置)会出现长时间超时,如果没有代理,这将是一个更大的问题,因为连接数越多。API无法以编程方式更改它们,但您可以通过JVM系统属性进行更改-请参阅我的回复帖子。谢谢-我现在在实时系统上使用
-Dsun.net.httpserver.maxReqTime=60000-Dsun.net.httpserver.maxRspTime=60000
。我将补充另一条评论,看看它是否在几天内有效。很抱歉,我不能完全理解:这难道不意味着挂起时间会变短吗?我的服务通常的响应时间少于1秒,因此30秒的冻结是不可接受的。我还应该提到,所有这些都是在低负载情况下发生的——服务器每小时只收到大约100个请求。应该意味着根本没有挂起或很长时间的无响应等待。我怀疑当所有线程都忙于从套接字读取数据,等待输入,但不再有来自浏览器的输入时,服务器会停止响应。例如,浏览器后退按钮/关闭/取消。建议的设置应该意味着线程在合理的时间内读取套接字超时,从而可以实际处理新的用户请求。i、 e.池中忙于等待读取的线程与可供处理的线程之间的平衡发生了重大变化。请注意,默认设置意味着无限等待-即真正的“挂起”。将MaxrOptime和maxReqTime设置为30或10会有很大帮助,但它们不能完全解决问题,即挂起时间更短,频率更低。我目前怀疑SSL是问题所在,例如,我无法使用pingdom这样的监控网站测试我的服务,因为我的服务不接受SSLv2请求,只接受SSLv3。一些浏览器可能也会出现同样的问题。我们现在也要做的是使用
Ht
  httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length());  
  final OutputStream os = httpExchange.getResponseBody();  
  os.write( response.getBytes() );  
  os.close();