10

私はhtmlunitを使用してWebクローラーを開発しており、必要なタイムアウトをすべて追加しましたが、Java VisualVMを使用してスレッドダンプを実行すると、クロールされたWebサイトのサーバーが応答しないとアプリがハングすることに気付きました:

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 アプリによって開かれたソケット接続のリストを取得し、それを使用してソケットを終了する方法はありますか?
4

3 に答える 3

11

Java ネイティブ メソッドを使用している場合、呼び出しが実際に何らかのイベントを待ってブロックされていても、スタック トレースには RUNNABLE と表示されると思います。本質的に、ネイティブ メソッドが実際に何を行っているかを Java が知る方法はないと思います。そのため、Java はこれらの呼び出しに RUNNABLE のフラグを立てます。私は socketRead0() と socketAccept() でこれを見てきました - どちらも通常ブロックします。

サーバーが応答しない場合にリクエストがタイムアウトになるが、サーバーが単にビジー状態の場合に備えて短すぎないように、タイムアウトを適切な長さに設定する必要があります。アプリケーションは、複数のスレッドを使用するように作成する必要があります。十数個のスレッドを実行してみて、各スレッドが応答を最大 5 秒または 10 秒待機するようにします。少数のスレッドを待機させることによるオーバーヘッドは事実上ありません。また、Web スパイダーを作成するときにサーバーに大量のリクエストを送信しないように注意する必要があります。

于 2012-09-22T17:50:22.473 に答える
6

関連する可能性のあるブログ投稿を次に示します

つまり、解決策は、ソケットのタイムアウトが定義されていることを確認することです。デフォルトは 0 で、タイムアウトなしを意味します。正確には、それはライブラリに依存しますが、この場合はどうやらcom.gargoylesoftware.htmlunit. 一見すると正しいメソッドはcom.gargoylesoftware.htmlunit.WebClient.setTimeoutかもしれません。

于 2013-03-25T09:59:05.347 に答える