ObjectInputStream.readObject() навсегда зависает в процессе взаимодействия с сокетом

Я столкнулся с проблемой связи через сокет в системе Linux, процесс связи такой, как показано ниже: клиент отправляет сообщение, чтобы попросить сервер выполнить вычислительную задачу, и дождаться сообщения о результате от сервера после ее завершения.

Но клиент зависает, ожидая сообщения о результате, если задача стоит долго, например около 40 минут, хотя со стороны сервера сообщение о результате было записано в сокет для ответа клиенту, но обычно оно может получите сообщение с результатом, если задача стоит мало времени, например, одна минута. Кроме того, эта проблема возникает только в пользовательской среде, процесс коммуникации в нашей тестовой среде работает нормально.

Я подозревал, что причиной этой проблемы является то, что значение времени ожидания сокета по умолчанию отличается в среде пользователя и в среде тестирования, но следующие значения идентичны в этих двух средах, а также в клиенте и на сервере.

getSoTimeout:0
getReceiveBufferSize:43690
getSendBufferSize:8192
getSoLinger:-1
getTrafficClass:0
getKeepAlive:false
getTcpNoDelay:false

коды на CLient выглядят так:

Message msg = null;
ObjectInputStream in = client.getClient().getInputStream();
//if no message readObject() will hang here
while ( true ) {
  try {
   Object recObject = in.readObject();
   System.out.println("Client received msg.");
   msg = (Message)recObject; 
   return msg;
       }catch (Exception e) {
    e.printStackTrace();
    return null;
   }
}

коды на сервере похожи,

ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
  MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
  socketOutStream.writeObject(msgJobComplete);
  }catch(Exception e) {
    e.printStackTrace();
  }

чтобы решить эту проблему, я добавил метод сброса и сброса, но проблема все еще существует:

ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
   MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
   socketOutStream.flush();
   logger.debug("AbstractJob#reply to the socket");
   socketOutStream.writeObject(msgJobComplete);
   socketOutStream.reset();
   socketOutStream.flush();
   logger.debug("AbstractJob#after Flush Reply");
 }catch(Exception e) {
    e.printStackTrace();
            logger.error("Exception when sending MessageJobComplete."+e.getMessage());
 }

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

И для сокета, использующего протокол Tcp/Ip для связи, проблема связана с долгой задачей времени, так что, какие значения о tcp могут повлиять на время ожидания сокета?

После анализа логов я обнаружил, что после записи сообщения в сокет исключений не было. Но всегда через 15 минут во фрагменте кода objectInputStream.readObject() на стороне сервера возникают исключения, которые используются для приема запроса от клиента. Однако значение socket.getSoTimeout равно 0, поэтому очень странно, что было сгенерировано исключение тайм-аута.

{2012-01-09  17:44:13,908} ERROR java.net.SocketException: Connection timed out
   at java.net.SocketInputStream.socketRead0(Native Method)
   at java.net.SocketInputStream.read(SocketInputStream.java:146)
   at sun.security.ssl.InputRecord.readFully(InputRecord.java:312)
   at sun.security.ssl.InputRecord.read(InputRecord.java:350)
   at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:809)
   at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:766)
   at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
   at sun.security.ssl.AppInputStream.read(AppInputStream.java:69)
   at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265)
   at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558)
   at  java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568)
   at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314)
   at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)

так почему генерируются исключения тайм-аута соединения?

2 ответа

Решение

Эта проблема решена. с использованием tcpdump захватывать потоки сообщений. Я обнаружил, что в то время как на уровне приложений, ObjectOutputStream.writeObject() Метод вызывался, на уровне TCP, много раз [TCP ReTransmission] были найдены.

Итак, я пришел к выводу, что связь может быть разорвана, хотя с помощью netstat -an Команда состояние соединения TCP еще был ESTABLISHED,

Поэтому я написал тестовое приложение, чтобы периодически отправлять тестовые сообщения в виде сердечных сообщений с Сервера. Тогда эта проблема исчезла.

read() методы java.io.InputStream блокируют вызовы. Это означает, что они ждут "вечно", если они вызваны, когда в потоке нет данных для чтения.

Это вполне ожидаемое поведение и согласно опубликованному контракту в javadoc, если сервер не отвечает.

Если вы хотите неблокирующее чтение, используйте java.nio.* классы.

Другие вопросы по тегам