简体   繁体   English

通过TCP套接字的ObjectOutputStream

[英]ObjectOutputStream over a TCP Socket

I wrote a peer-to-peer networked game in Java using the java.net package and for some reason the Socket between the client and the server closes or gets corrupted. 我使用java.net程序包用Java编写了对等网络游戏,由于某种原因,客户端和服务器之间的套接字关闭或损坏。 I am calling this "peer-to-peer" because one of the clients also runs a server class, which is just a custom class I wrote that accepts Socket connections - one from the other computer and one from the client computer. 我之所以称其为“点对点”,是因为其中一个客户端还运行服务器类,这是我编写的接受套接字连接的自定义类-一个来自另一台计算机,另一个来自客户端计算机。 The connection is being used to move objects back and forth using ObjectOutputStream and ObjectInputStream. 该连接用于使用ObjectOutputStream和ObjectInputStream来回移动对象。

The Socket error happens irregularly. 套接字错误不定期发生。 The connection is usually open for 5-10 minutes before there is a problem. 在出现问题之前,连接通常会打开5-10分钟。 Sometimes it closes when a new game is started, other times it closes while a game is in progress. 有时它在新游戏开始时关闭,而其他时候在游戏进行时关闭。

  1. Should I be using keepAlive to keep the connection open? 我应该使用keepAlive保持连接打开吗?
  2. Does anyone have a suggestion on how I should go about troubleshooting this problem? 有人对我应该如何解决此问题有建议吗?

Here is the code generating the error: 这是生成错误的代码:

/**
 * 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);
      }

Here is the error message and stack trace: 这是错误消息和堆栈跟踪:

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

There are two sockets (two streams) active, one for each client. 有两个活动套接字(两个流),每个客户端一个。 When the other socket throws the same error, I am seeing invalid type code: FF 当另一个套接字抛出相同的错误时,我看到无效的类型代码:FF

Stack Trace 堆栈跟踪

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)

When creating networking applications it is very important to introduce network I/O logging early in the development. 创建网络应用程序时,在开发的早期阶段引入网络I / O日志记录非常重要。 It will help you troubleshoot simple bugs like connection breaks and incorrect data being sent or received. 它将帮助您解决简单的错误,例如连接断开以及发送或接收的数据不正确。

I assume that you have connection problems in your test environment: that is on local network? 我假设您在测试环境中存在连接问题:那是在本地网络上吗? Can you describe your client? 您能描述一下您的客户吗? Is it a mobile device? 它是移动设备吗?

If your application needs connection to be constantly open I would recommend implementing some reconnect logic. 如果您的应用程序需要持续打开连接,那么我建议您实现一些重新连接逻辑。 That is if connection is broken (you detect it when performing I/O operation) you try to re-establish it with the peer. 也就是说,如果连接断开(在执行I / O操作时检测到连接),则尝试与对等方重新建立连接。

UPDATE: 更新:

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

What will happen if there are several objects serialized in the available bytes? 如果在可用字节中序列化了多个对象,将会发生什么? What does in.readObject() ? in.readObject()是什么? Does it read required amount of bytes for object serialization or everything that is available? 它是否读取对象序列化所需的字节数或所有可用的字节数?

IMO the possible reason of the behavior you see is that the code does not expect several objects can be received at once and stored in the receive buffer. IMO您看到的行为的可能原因是该代码并不希望可以一​​次接收多个对象并将其存储在接收缓冲区中。 Also receive buffer can contain parts of the objects (eg object1 + two bytes of the object2). 同样,接收缓冲区可以包含对象的一部分(例如,object1 + object2的两个字节)。

TCP is a stream protocol and therefore you cannot determine message end easily. TCP是一种流协议,因此无法轻松确定消息结束。 You should implement protocol that will determine the start and end of the message being transmitted. 您应该实施协议,该协议将确定正在传输的消息的开始和结束。 In the code from you 在你的代码中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM