Crawler оставляет много УСТАНОВЛЕННЫХ сокетов TCP для некоторых серверов - PullRequest
2 голосов
/ 23 января 2011

У меня есть веб-сканер Java. Я заметил, что для небольшого количества серверов, которые я сканирую, у меня остается большое количество УСТАНОВЛЕННЫХ сокетов:

joel@bohr:~/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, пока я закрываю поток ввода / ошибок и все данные считываются из потока. Я также понимаю, что если выдается исключение, то, пока поток ввода / ошибок закрыт (если не нулевой), сокет, хотя и не используется повторно, будет закрыт. ( Java-обработка 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();
   }
  }

Я заметил, что для сайта, где это происходит, я получаю много исключений IOException при выполнении запросов GET из-за:

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

Я почти уверен, что справляюсь с этим, правильно закрывая сокет. Неужели это действительно так, или я что-то не так делаю? Может ли это быть результатом неправильного использования keep-alive - и если да, то как это исправить? Я бы предпочел не включать выключение поддержки, чтобы решить проблему.

РЕДАКТИРОВАТЬ : я проверил настройку следующего свойства:

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

При отправке заголовка Connection: close отключены постоянные tcp-соединения и все сокеты в итоге очищаются. Таким образом, может показаться, что проблема, которую я вижу, действительно связана с keep-alive и сокетами, которые закрываются неправильно, даже после закрытия входного потока.

EDIT2 - может ли быть так, что один сокет создается при каждом перенаправлении запроса? Там, где эта проблема заметна, запрос перенаправляется 20 раз, прежде чем выдается исключение, указанное выше. Если бы это было так, есть ли способ ограничения количества перенаправлений на URLConnection?

1 Ответ

0 голосов
/ 23 января 2011

Вам необходимо переместиться conn.disconnect() в ваш finally раздел. Поскольку вы отключаетесь только в случае возникновения исключения.

...