2016-03-31 11 views
0

は、私はこのような構築基本的にされているJava NIOチャネルを介して、データのストリームを送信読まれていませんパケットidはそれを解析する方法を指示する)。一部のデータをローカルに送信しようとするとうまくいきますが、Windows Server 2012で実行しようとすると、負の値や大きすぎる値などの無効なパケットサイズの値が読み取られます。のJava NIOチャネルデータが正しく

クライアント出力:最後に

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) 

数字は、あなたがそれのためにバッファを準備しようとしているときに例外につながり、1つのとんでもない数に気づくことができ、読み取りパッケージの大きさ、です。

サーバー出力:

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また、これらの2つのintを含むが、2つの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

あなたが送信者と同期して取得しているではなく、ローカルに、常に再現可能ではなく、来て続けています。あなたの受信コードを詳細に解析していませんが、可能なすべてのケースを処理せず、パケット長を正しく読み取ることはできません。あなたは長さの単語として、足の部分を読んでいる。あなたはあなたのロジックを再考する必要があります。

なぜこれでNIOを使用しているのですか? DataInputStreamで、readInt()readFully()を連続して使用して、EOFExceptionがスローされるまで試してみてください。

+0

私は複数のクライアントを同時に処理しなければならず、他のすべてをブロックする可能性のある1人の人を待つのではなく、実際に要求を送信している人に反応したいからです。だから、同期が外れることはどういう意味ですか?私はこれを見ることができるいくつかの文書がありますか? – user3088126

+0

私はあなたが長さの単語としてパケットの一部を読んでいることを意味します。と言いました。シンプルなコンセプトで、ドキュメントは必要ありません。 NIOをブロッキングモードで使用していますが、これはストリームを使用するのと同じです。そうでなければ、 'select()'ループの代わりにreadループを使うことで、ノンブロッキングモードでそれを悪用しています。どちらの方法でも、あなたのコメントに記載された目的を達成できない場合があります。クライアントのサービスを開始すると、他のすべてのクライアントが待機します。 – EJP

+0

私はselectループを使用しますが、このコードセグメントにはありません。すべての着信パケットは他のスレッドで処理されるため、このパケットはブロックされません。 – user3088126

関連する問題