2012-09-22 13 views
8

Estoy desarrollando un cralwer web con htmlunit y he agregado todo el tiempo de espera requerido, pero noté que la aplicación se bloquea cuando el servidor de algún sitio web rastreado no responde cuando uso Java VisualVM para hacer un volcado de hilo:Java socketRead0 Issue

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) 

Esto es realmente frustrante ya que no tengo control de esos servidores. Este problema está afectando seriamente el rendimiento de mi aplicación.

Pregunta:

  1. ¿Cómo puedo solucionar este problema?
  2. ¿Hay alguna manera de obtener una lista de conexión de socket abierta por una aplicación Java y usarla para terminar el socket, como simular que el servidor cerró la conexión?
+0

¿Cómo hace usted que el hilo esté bloqueado? su estado es runable. Si estaba bloqueado, habría estado "En espera" o "Bloqueado". –

+0

Obviamente, no ha agregado todos los tiempos de espera requeridos ;-) ¿Puede mostrar qué tiempos de espera tiene? –

+0

@Ravi Bhatt, no dije que el hilo fuera bloque. @ Roger Lindsjö, agregué todo el tiempo de espera requerido, lo que soy particular es el bloqueo en java.net.SocketInputStream.socketRead0 – John

Respuesta

9

Creo que cuando está en un método nativo de Java, el seguimiento de pila dirá RUNNABLE incluso si la llamada está realmente bloqueada esperando algún evento. En esencia, no creo que Java tenga ninguna forma de saber lo que realmente está haciendo un método nativo, por lo que marca estas llamadas como RUNNABLE. Lo he visto con socketRead0() y socketAccept() - ambos bloquean normalmente.

Debe establecer su tiempo de espera en un período de tiempo razonable para que su solicitud se agote si el servidor no responde pero no es demasiado corto en caso de que el servidor esté simplemente ocupado. Su aplicación debe escribirse para usar múltiples hilos. Intentaría ejecutar una docena o más de hilos y hacer que cada hilo espere hasta cinco o diez segundos para obtener una respuesta. Prácticamente no hay gastos generales en tener un puñado de hilos esperando. También debe tener cuidado de no bombardear un servidor con muchas solicitudes al escribir una araña web.

5

Aquí es un blog que está posiblemente relacionado: http://javaeesupportpatterns.blogspot.fi/2011/04/javanetsocketinputstreamsocketread0.html

En resumen, la solución es asegurarse de que el tiempo de espera socket se define. El valor predeterminado es 0, lo que significa que no hay tiempo de espera. ¿Cómo exactamente? Eso depende de la biblioteca, en este caso aparentemente com.gargoylesoftware.htmlunit. A primera vista, el método correcto podría ser com.gargoylesoftware.htmlunit.WebClient.setTimeout.

1

Si su servidor Java está en Windows, su último recurso es SysInternals TCPView.

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

Desde ella se va a ver la lista de todos los procesos y todos los puertos locales y remotos, que incluirá la aplicación Java. Tendrás que elegir la conexión correcta para cerrar, y después de eso, el subproceso Java arrojará una excepción y finalizará.

Por supuesto, existe el riesgo de cerrar la conexión incorrecta. Después de todo, este método es el último recurso.