Я посылаю поток данных через Java NIO канал, который в основном строят так:Java данных NiO канал не правильно читать
<int:size of packet><int:packet id><packet data>
пакет данных заполнен различными типами данных в определенном порядке (идентификатор пакета указывает, как его анализировать). Когда я пытаюсь отправить некоторые данные локально, он работает нормально, но как только я попытаюсь запустить его на 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 пакета).
Эта ошибка не всегда воспроизводимость, но продолжает идти, но не локально (по крайней мере, я никогда не сталкивались с этим)
Я использую NIO, потому что мне приходится обрабатывать несколько клиентов одновременно и только хочу реагировать на людей, которые действительно отправляют запросы, а не ждут одного человека, который может заблокировать все остальное. Итак, что именно вы подразумеваете, выйдя из синхронизации? Есть ли какой-нибудь документ, который я могу посмотреть? – user3088126
Я имею в виду, что вы читаете часть пакета как слово длины. То, что я сказал. Простая концепция, не требуется документа. Вы используете NIO в режиме блокировки, который ничем не отличается от использования потоков. Или вы неправильно используете его в неблокирующем режиме, используя циклы чтения вместо 'select()' loop. В любом случае вы не достигаете цели, указанной в вашем комментарии: как только вы начинаете обслуживать клиента, все остальные ждут. – EJP
Я использую цикл выбора, но он не находится в этом сегменте кода. Все входящие пакеты обрабатываются в других потоках, поэтому они не блокируют это. – user3088126