ObjectOutputStream через сокет TCP - PullRequest
0 голосов
/ 08 марта 2012

Я написал одноранговую сетевую игру на Java с использованием пакета java.net, и по какой-то причине сокет между клиентом и сервером закрывается или поврежден. Я называю это «одноранговым», потому что один из клиентов также запускает серверный класс, который является просто написанным мной пользовательским классом, который принимает соединения Socket - один с другого компьютера и один с клиентского компьютера. Соединение используется для перемещения объектов вперед и назад с использованием ObjectOutputStream и ObjectInputStream.

Ошибка сокета происходит нерегулярно. Соединение обычно открывается в течение 5-10 минут, прежде чем возникает проблема. Иногда он закрывается, когда запускается новая игра, в других случаях он закрывается во время игры.

  1. Должен ли я использовать keepAlive, чтобы держать соединение открытым?
  2. У кого-нибудь есть предложения по устранению этой проблемы?

Вот код, генерирующий ошибку:

/**
 * Continually checks for messages to be read in. Then it
 * sends the messages to processMessage if a message is available.
 */
   public void listenForMessages() {
      int availableBytes;
      Object obj = null;
      try {
         availableBytes = socketStream.available();
         if (availableBytes >5) {
            obj = in.readObject();
            message = (ClientMessage) (obj);
            processMessage();
         }
      }
      catch(java.io.StreamCorruptedException utoh) {
          System.out.println("Read failed: " + utoh);
          try {
              System.out.println("Number of Bytes available: " + socketStream.available());
              utoh.printStackTrace();
              System.out.println("Attempting to close socked.");
              socketStream.close();
          }
          catch(IOException ioe) { 
              System.out.println("Unable to close: " + ioe.toString());
          }              
      }
      catch(IOException e) {
         System.out.println("Read failed" + e);
      }

Вот сообщение об ошибке и трассировка стека:

Read failed: java.io.StreamCorruptedException: invalid type code: 00
Number of Bytes available: 100

Есть два активных сокета (два потока), по одному для каждого клиента. Когда другой сокет выдает ту же ошибку, я вижу неправильный код типа: FF

Трассировка стека

java.io.StreamCorruptedException: invalid type code: 00
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1355)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1946)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1870)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at thornworks.quiz.PlayerInterface.listenForMessages(PlayerInterface.java:227)
at thornworks.quiz.PlayerInterface.actionPerformed(PlayerInterface.java:214)
at javax.swing.Timer.fireActionPerformed(Timer.java:291)
at javax.swing.Timer$DoPostEvent.run(Timer.java:221)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:641)
at java.awt.EventQueue.access$000(EventQueue.java:84)
at java.awt.EventQueue$1.run(EventQueue.java:602)
at java.awt.EventQueue$1.run(EventQueue.java:600)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:611)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

1 Ответ

1 голос
/ 08 марта 2012

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

Я предполагаю, что у вас проблемы с подключением в вашей тестовой среде: то есть в локальной сети? Можете ли вы описать своего клиента? Это мобильное устройство?

Если вашему приложению требуется постоянное соединение, я бы порекомендовал реализовать некоторую логику повторного подключения. То есть, если соединение разорвано (вы обнаруживаете это при выполнении операции ввода / вывода), вы пытаетесь восстановить его с помощью партнера.

UPDATE:

if (availableBytes >5) {
    obj = in.readObject();
    message = (ClientMessage) (obj);
    processMessage();
}

Что произойдет, если в доступных байтах сериализовано несколько объектов? Что означает in.readObject () ? Читает ли он необходимое количество байтов для сериализации объекта или все, что доступно?

IMO возможная причина поведения, которое вы видите, состоит в том, что код не ожидает, что несколько объектов могут быть получены одновременно и сохранены в приемном буфере. Также приемный буфер может содержать части объектов (например, object1 + два байта объекта2).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...