Java socketRead0问题

我正在使用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) 

这真是令人沮丧,因为我无法控制这些服务器。 此问题严重影响了我的应用程序的性能。

题:

  1. 我该如何解决这个问题?
  2. 有没有办法获取Java应用程序打开的套接字连接列表并使用它来终止套接字,比如模拟服务器关闭连接?

我相信当你使用Java本机方法时,即使调用实际上被阻塞等待某个事件,堆栈跟踪也会说RUNNABLE。 本质上,我不相信Java有任何方法可以知道本机方法实际上在做什么,所以它将这些调用标记为RUNNABLE。 我已经看到了socketRead0()和socketAccept() – 这两者通常都会阻塞。

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

这是一篇可能相关的博客文章: http : //javaeesupportpatterns.blogspot.fi/2011/04/javanetsocketinputstreamsocketread0.html

简而言之,解决方案是确保定义套接字超时。 默认值为0,表示没有超时。 究竟是什么,这取决于图书馆,在这种情况下显然是com.gargoylesoftware.htmlunit 。 快速浏览一下正确的方法可能是com.gargoylesoftware.htmlunit.WebClient.setTimeout 。

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

http://technet.microsoft.com/en-us/sysinternals/bb897437.aspx

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

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