我有一个使用非阻塞套接字的服务器,nio。服务器在一个单独的线程中工作,还有另一个名为Game的线程。游戏线程持有服务器对象并使用server.sendMessage,服务器线程只读取数据。当我在一个while循环中顺序调用sendMessage两次2个数据包时,片刻之后我在客户端得到“java.io.StreamCorruptedException:invalid stream header:6B6574B4”错误。
服务器代码的一部分:
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);
}
答案 0 :(得分:1)
我的猜测(来自你所包含的少量代码)是你根本没有描述你的消息。即使您单独发送2条消息,io层也可能以各种方式拆分/组合这些消息,以便接收方获得附加到先前消息的一条消息的一部分。您应该使用某种“消息”协议向接收器准确地指示要消耗多少字节,以便它可以正确地解析每个传入消息(例如,首先写入消息字节长度,然后写入消息字节)。
作为附注,write()
方法不能保证在一次调用中写入所有字节,因此您应该处理返回值并根据需要写入剩余的字节。
答案 1 :(得分:1)
在写之前需要flip()
,之后需要compact()
,你需要停止假设一个write()
写入整个缓冲区。它返回一个值的原因。您需要循环,或者如果您处于非阻塞模式,则需要按如下方式进行: