1

我正在尝试将对象从客户端(普通 IO)传输到服务器(NIO)。传输工作正常,直到对象达到一定大小,然后服务器将抛出“StreamCorruptException”说“无效类型代码”。

服务端调用的方法如下:

  private void read(SelectionKey key) throws IOException, ClassNotFoundException {
    SocketChannel chan = (SocketChannel) key.channel();

    //read message object
    ByteBuffer buf = ByteBuffer.allocate(1024);
    ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.capacity());
    int length = 0;
    int totalRead = 0;
    int read = chan.read(buf);
    System.out.println("read data " + read);
    if (read >= 4) {
      length = IoUtil.readInt(buf.array(), 0);
      bos.write(buf.array());
      buf.rewind();
      totalRead += read;
      LogUtil.log("length of data message is " + length);
    }
    while (totalRead < length) { //read until we get no more data
      read = chan.read(buf);
      if (read == -1) break;
      if (read == 0) continue;
      totalRead += read;
      System.out.println("I've read " + read + " bytes. Total amount of bytes " + totalRead);
      bos.write(buf.array());
      buf.rewind();
    }

    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray(), 4, length);
    ObjectInputStream inFromClient = new ObjectInputStream(bis);

    Message msg = (Message) inFromClient.readObject();

    SocketAddress sa = chan.socket().getRemoteSocketAddress();
    LogUtil.log(msg.getIdentifier() + "-Message von " + sa);


    commData.handleMessage(sa, msg);

  }

我预先设置了对象的大小以使 NIO 可以很好地发挥作用。我在这里想念什么?

4

1 回答 1

2

您必须考虑到消息可能是碎片化的(我怀疑这是在这里发生的)或合并。这意味着您不能假设消息的开头和消息的结尾将在读取的开头或结尾。(它通常用于它们之间有明显中断的小消息,但这会随机失败)

安全的方法是在开始时发送一个长度并读取,直到你有那个长度。如果您有更多,请保留额外的内容以供下次阅读。

于 2013-07-09T14:23:24.007 回答