2013-05-08 18 views
0

我有一台服务器使用非阻塞套接字nio。服务器在单独的线程中工作,并且有另一个称为游戏的线程。游戏线程保存服务器对象并使用server.sendMessage,服务器线程只读取数据。当我在一个while循环中连续两次调用sendMessage两次数据包后,我在客户端得到“java.io.StreamCorruptedException:invalid stream header:6B6574B4”错误。服务器代码Sequentally Channel Write在Java.NIO中发送损坏的数据

部分:

public void write(SelectionKey channelKey, byte[] buffer) { 
    if (buffer != null) { 
     int bytesWritten; 
     try { 
      SocketChannel channel = (SocketChannel) channelKey.channel(); 
      synchronized (channel) { 
       bytesWritten = channel.write(ByteBuffer.wrap(buffer)); 
      } 
      if (bytesWritten == -1) { 
       resetKey(channelKey); 
       disconnected(channelKey); 
      } 
     } catch (Exception e) { 
      resetKey(channelKey); 
      disconnected(channelKey); 
     } 
    } 
} 

public void broadcast(byte[] buf, SelectionKey fr) { 
    synchronized (clientList) { 
     Iterator<SelectionKey> i = clientList.iterator(); 
     while (i.hasNext()) { 
      SelectionKey key = i.next(); 
      if (fr != key) 
       write(key, buf); 
     } 
    } 
} 

public synchronized void sendMessage(Packets pk) { 
    broadcast(pk.toByteArray(), null); 
} 

回答

1

我猜(从已包含的代码量小),就是你不划定您的邮件在所有。即使您分别发送2条消息,io层也可以以各种方式拆分/组合这些消息,以便接收者获得附加到先前消息的消息的一部分。你应该使用某种“消息”协议向接收者指出要消耗多少字节,以便它可以正确解析每个传入消息(例如先写入消息字节长度,然后再写入消息字节)。

作为一个备注,write()方法不保证在一次调用中写入所有字节,所以您应该处理返回值并根据需要写入其余字节。

+0

+1对于“循环”,但你应该提到循环不是字面上的while(!allWritten){write(lastPartOfBuf();}',它是异步操作链。 – 2013-05-09 01:00:50

0

您需要在写入之前flip()以及之后的compact(),并且您需要停止假设一个write()写入整个缓冲区。它返回一个值的原因。您需要循环,或者如果您处于非阻塞模式,则需要按以下步骤进行操作:

  1. 写。
  2. 如果写入未完全完成,请为OP_WRITE注册通道并返回到选择循环。
  3. 当通道变为可写时,再次尝试写入,如果仍然没有完成,只保持循环。
  4. 否则取消注册OP_WRITE。