2011-01-23 14 views
2

私はJava Webクローラを持っています。私はなぜ把握望めないクローラはいくつかのサーバに多くのESTABLISHED TCPソケットを残します

[email protected]:~/tmp/test$ lsof -p 6760 | grep TCP 
java 6760 joel 105u IPv6  96546  0t0  TCP bohr:55602->174.143.223.193:www (ESTABLISHED) 
java 6760 joel 109u IPv6  96574  0t0  TCP bohr:55623->174.143.223.193:www (ESTABLISHED) 
java 6760 joel 110u IPv6  96622  0t0  TCP bohr:55644->174.143.223.193:www (ESTABLISHED) 
java 6760 joel 111u IPv6  96674  0t0  TCP bohr:55665->174.143.223.193:www (ESTABLISHED) 

いずれかのサーバー&にこれらの数十があるかもしれません:私は私が確立ソケットの多数を残していますクロールサーバの数が少ないためという私が気づきました彼らは開いたままです。

私はHttpURLConnectionを使用して接続を確立し、データを読み取ります。 HTTP 1.1およびkeep-aliveはオンです(デフォルト)。入力/エラーストリームを閉じ、すべてのデータがストリームから読み込まれている限り、リモートサーバーへの基底のtcpソケットはJavaのHttpURLConnectionによって再利用されることは私の理解です。また、例外がスローされた場合、入力/エラーストリームが閉じられている限り(nullでない場合)、ソケットは再び再利用されませんが、閉じられます。 (java handling of http-keepalive

私の省略コードは次のようになります。

InputStream is = null; 
    try { 
    HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection(); 
    conn.setReadTimeout(10000); 
    conn.setConnectTimeout(10000); 
    conn.setRequestProperty("User-Agent", userAgent); 
    conn.setRequestProperty("Accept", "text/html,text/xml,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); 
    conn.setRequestProperty("Accept-Encoding", "gzip deflate"); 
    conn.setRequestProperty("Accept-Language", "en-gb,en;q=0.5"); 
    conn.connect(); 

    try { 
    int responseCode = conn.getResponseCode(); 
    is = conn.getInputStream(); 

    } catch (IOException e) {  
    is = conn.getErrorStream(); 
    if (is != null){ 
    // consume the error stream, http://download.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html 
    StreamUtils.readStreamToBytes(is, -1 , MAX_LN); 
    } 
    throw e; 
    } 

    String type = conn.getContentType(); 

    byte[] response = StreamUtils.readStream(is); 
    // do something with content 


    } catch (Exception e) { 
     conn.disconnect(); // don't try to re-use socket - just be done with it. 
    throw e; 

} finally { 
    if (is != null) { 
    is.close(); 
    } 
    } 

私は、これが起こっているサイトのために私が起因して、GET要求を行う場合にスローさIOExceptionsの多くを得ることに気付きました

java.net.ProtocolException: Server redirected too many times (20) 

私はこれを処理していると確信しています。ソケットを正しく閉じています。それは本当にこれ、または私が間違っている何か他のものか?それはキープアライブを誤って使用した結果かもしれません。むしろ問題を解決するためにキープ・アライブをオフにする必要はありません。

EDIT:私は次のプロパティを設定しテストしてみた:

 conn.setRequestProperty("Connection", "close"); // supposed to disable keep-alive 

Connection: closeヘッダは持続的なTCP接続を無効にし、すべてのソケットが最終的にクリーンアップされて送信します。だから、私が見ている問題は実際には入力ストリームを閉じた後でさえ、keep-aliveとソケットが正しく閉じられていないことと思われます。

EDIT2 - リクエストがリダイレクトされるたびに1つのソケットが作成される可能性がありますか?この問題が顕著な場合は、上記の例外がスローされる前に要求が20回リダイレクトされます。この場合、URLConnectionのリダイレクト数を制限する方法はありますか?

答えて

0

conn.disconnect()finallyセクションに移動する必要があります。それは例外がスローされた場合にのみ切断されます。

+0

私は故意に最後から切断を残しました。切断を呼び出すと、基礎となるtcpソケットを再利用することができなくなります(キープアライブを使用する点が無効になります)。私が見ているのは、同じサーバーに対して、同じソケットが別のリクエスト(および別のURLConnectionインスタンス)で再利用されていることです。処理中に例外が発生した場合にのみ切断を呼び出すか、すべてのコンテンツを読み取ることができません(ソケットは再利用できないため)。 – Joel

関連する問題