我通过java nio频道发送数据流,基本上是这样构建的:
<int:size of packet><int:packet id><packet data>
数据包数据按特定顺序填充不同的数据类型(数据包ID告诉如何解析它)。当我尝试在本地发送一些数据时它工作正常,但是当我尝试在Windows Server 2012上运行它时,它会读取无效的数据包大小值,例如负值或太大的值:
客户端输出:
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkRequest (size: 24)
2988
-2032198748
java.lang.IllegalArgumentException
at java.nio.ByteBuffer.allocate(Unknown Source)
at network.ClientSocket.run(ClientSocket.java:66)
at java.lang.Thread.run(Unknown Source)
最后的数字是读取包的大小,你可以注意到一个荒谬的数字,它会在尝试为它准备一个缓冲区时导致异常。
服务器输出:
Sending packet: network.PacketLoginAck (size: 16)
Sending packet: network.PacketPlayerData (size: 951)
Sending packet: network.PacketWorldInfo (size: 33)
Received packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkData (size: 2988) // This is the first package that still worked
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Received packet: network.PacketChunkRequest (size: 24)
Sending packet: network.PacketChunkData (size: 2518)
Sending packet: network.PacketChunkData (size: 2741)
Sending packet: network.PacketChunkData (size: 2966)
Sending packet: network.PacketChunkData (size: 2449)
Sending packet: network.PacketChunkData (size: 2769)
Sending packet: network.PacketChunkData (size: 1862)
Sending packet: network.PacketChunkData (size: 2526)
Sending packet: network.PacketChunkData (size: 2353)
PacketChunkRequest包含两个整数,两个坐标,而PacketChunkData也包含这两个整数,加上二进制数据,这是一个int,用于描述数据的长度,后跟实际数据。
我发送的数据如下:
for(Packet p : packets) {
System.out.println("Sending packet: "+p.getClass().getName()+" (size: "+p.length()+")");
ByteBuffer b = p.getBuffer();
while (b.hasRemaining()) {
clientChannel.write(b);
}
b.clear();
sentPackages.add(p);
}
这是读取数据包的代码:
List<ByteBuffer> packets = new ArrayList<ByteBuffer>();
ByteBuffer bin = null;
int packetLength = 0;
while((bytesRead = channel.read(buffer)) > 0) {
buffer.flip();
while(buffer.remaining() > 0) {
if(packetLength == 0) {
if(buffer.remaining() < 4) break;
packetLength = buffer.getInt();
System.out.println(packetLength); // This is the output of the length
bin = ByteBuffer.allocate(packetLength); // This is where the error happens
}
int readSize = Math.min(packetLength, buffer.remaining());
buffer.limit(buffer.position() + readSize);
bin.put(buffer);
buffer.limit(bytesRead);
packetLength -= readSize;
if(packetLength == 0) {
bin.flip();
packets.add(bin);
}
}
byte[] remaining = new byte[buffer.remaining()];
for(int i = 0; buffer.remaining() > 0; i++) remaining[i] = buffer.get();
buffer.clear();
for(byte b : remaining) buffer.put(b);
}
此代码尝试通过将多少字节读入单个缓冲区作为数据包大小(包的第一个int)来重建一起发送的各个包。
这个错误并不总是可以重现,而是继续发生,但不是在本地(至少我从未遇到过)
答案 0 :(得分:0)
您与发件人不同步。我没有详细分析您的接收代码,但显然它没有处理所有可能的情况并正确地读取整数的数据包长度。你正在读长篇单词的一部分。你需要重新考虑你的逻辑。
我会质疑你为什么要使用NIO。尝试使用DataInputStream
,先后使用readInt()
和readFully()
,直到EOFException
被抛出。