Java socketRead0问题

Java socketRead0问题,java,sockets,Java,Sockets,我正在用htmlunit开发一个web cralwer,我已经添加了所有必需的超时,但我注意到当我使用Java VisualVM进行线程转储时,当某个已爬网网站的服务器没有响应时,应用程序会挂起: java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129

我正在用htmlunit开发一个web cralwer,我已经添加了所有必需的超时,但我注意到当我使用Java VisualVM进行线程转储时,当某个已爬网网站的服务器没有响应时,应用程序会挂起:

java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.net.SocksSocketImpl.readSocksReply(SocksSocketImpl.java:88)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:429)
at java.net.Socket.connect(Socket.java:525)
at com.gargoylesoftware.htmlunit.SocksSocketFactory.connectSocket(SocksSocketFactory.java:89)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:776)
at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:152)
at app.plugin.core.net.QHttpWebConnection.getResponse(QHttpWebConnection.java:30)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1439)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1358)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:307)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:373)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:358)
这确实令人沮丧,因为我无法控制这些服务器。此问题严重影响了我的应用程序的性能

问题:

  • 我如何解决这个问题
  • 是否有一种方法可以获取Java应用程序打开的套接字连接列表,并使用该列表终止套接字,例如服务器关闭连接的模拟

  • 我相信,当您使用Java本机方法时,堆栈跟踪将显示RUNNABLE,即使调用实际上在等待某个事件时被阻止。本质上,我认为Java无法知道本机方法实际在做什么,因此它将这些调用标记为可运行。我已经在socketRead0()和socketAccept()中看到了这一点,这两个函数通常都会阻塞


    您需要将超时设置为合理的时间长度,这样,如果服务器没有响应,您的请求将超时,但如果服务器很忙,则不会太短。您的应用程序应该编写为使用多线程。我会尝试运行十几个或更多的线程,让每个线程等待五到十秒钟的响应。让少数线程等待几乎没有开销。编写网络蜘蛛时,还应注意不要用大量请求轰炸服务器。

    以下是一篇可能与此相关的博客文章:


    简而言之,解决方案是确保定义了套接字超时。默认值为0,表示没有超时。确切地说,这取决于库,在本例中显然是
    com.gargoylesoftware.htmlunit
    。快速浏览一下,正确的方法可能是。

    如果您的Java服务器在Windows上,最后的方法是SysInternals TCPView

    从中,您将看到所有进程以及所有本地和远程端口的列表,其中包括您的Java应用程序。您必须选择正确的连接来关闭,然后,Java线程将抛出异常并结束

    当然,有关闭错误连接的风险。毕竟,这种方法是最后的手段

    2019年8月23日更新:

    当存在大量连接时,TCPView会变慢


    更快的选择是CurrPorts(来自NirSoft):

    如何确定线程被阻塞?它的状态是可运行的。如果它被阻止,它将被“等待”或“阻止”。显然,您没有添加所有必需的超时;-)你能告诉我你有哪些超时吗?@Ravi Bhatt,我没说线程被阻塞了。@Roger Lindsjö,我添加了所有必需的超时,我特别需要的是挂起java.net.SocketInputStream.socketRead0