2009-08-12 2 views
1

ちょっと、カスタムバイナリプロトコルを使用してパケットを分離する問題があります。 現在、サーバー側のコードは次のようになっています。バイナリプロトコルによるTCPフレーミング

public void HandleConnection(object state) 
    { 
     TcpClient client = threadListener.AcceptTcpClient(); 
     NetworkStream stream = client.GetStream(); 
     byte[] data = new byte[4096]; 

     while (true) 
     { 
      int recvCount = stream.Read(data, 0, data.Length); 
      if (recvCount == 0) break; 
      LogManager.Debug(Utility.ToHexDump(data, 0, recvCount)); 
      //processPacket(new MemoryStream(data, 0, recvCount)); 
     } 
     LogManager.Debug("Client disconnected"); 
     client.Close(); 
     Dispose(); 
    } 

私はパケットのヘキサ・ダンプを見てきましたが、パケット全体がワンショットで表示されることがあります。すべて20バイトとしましょう。それがフラグメント化されている場合、このデータをprocessPacket()メソッドに正しく渡すために、このデータをバッファリングする必要があります。私は(ushort)contentLengthのようなものをヘッダーに追加するだけで、1バイトのopcodeヘッダーのみを使用しようとしていますか?私は可能な限り軽量プロトコルを作ろうとしており、このシステムは非常に大きなパケット(< 128バイト)を送信しません。

私がテストしているクライアントサイドコードは次のとおりです。それはそれをめちゃくちゃに何もすることができれば

public void auth(string user, string password) 
    { 
     using (TcpClient client = new TcpClient()) 
     { 
      client.Connect(IPAddress.Parse("127.0.0.1"), 9032); 
      NetworkStream networkStream = client.GetStream(); 

      using (BinaryWriter writer = new BinaryWriter(networkStream)) 
      { 
       writer.Write((byte)0); //opcode 
       writer.Write(user.ToUpper()); 
       writer.Write(password.ToUpper()); 
       writer.Write(SanitizationMgr.Verify()); //App hash 
       writer.Write(Program.Seed); 
      } 
     } 
    } 

は私はわからない、とバイナリプロトコルは、C#が関与している、特にWeb上で多くの情報を、持っていないようです。コメントは参考になります。 =)

解決済みこれが正しいかどうかはわかりませんが、ハンドラに必要なものだけを与えるようです。

public void HandleConnection(object state) 
    { 
     TcpClient client = threadListener.AcceptTcpClient(); 
     NetworkStream stream = client.GetStream(); 
     byte[] data = new byte[1024]; 

     uint contentLength = 0; 
     var packet = new MemoryStream(); 
     while (true) 
     { 
      int recvCount = stream.Read(data, 0, data.Length); 
      if (recvCount == 0) break; 

      if (contentLength == 0 && recvCount < headerSize) 
      { 
       LogManager.Error("Got incomplete header!"); 
       Dispose(); 
      } 

      if(contentLength == 0) //Get the payload length 
       contentLength = BitConverter.ToUInt16(data, 1); 

      packet.Write(data, (int) packet.Position, recvCount); //Buffer the data we got into our MemStream 
      if (packet.Length < contentLength + headerSize) //if it's not enough, continue trying to read 
       continue; 

      //We have a full packet, pass it on 
      //LogManager.Debug(Utility.ToHexDump(packet)); 
      processPacket(packet); 

      //reset for next packet 
      contentLength = 0; 
      packet = new MemoryStream(); 
     } 
     LogManager.Debug("Client disconnected"); 
     client.Close(); 
     Dispose(); 
    } 

答えて

3

ただストリームとして扱う必要があります。特定のチャンク動作には依存しないでください。

必要なデータ量は常に同じですか?そうでない場合は、データの論理チャンクにプレフィックス(バイト数)を付けるためにプロトコルを変更する必要があります(可能な場合)。

この場合、あなたは片側BinaryWriterを使用しているので、TcpClient.GetStream()によって返さNetworkStreamBinaryReaderを取り付けることは最も簡単な方法のように思われます。あなたが本当にチャンクのすべてのデータを一度にキャプチャしたいのであれば、データの長さをプレフィックスにする考えに戻ってください。次に、すべてのデータが得られるまでループを繰り返します。

(あなたがが長さを読み込むための十分なデータを持っていることを確認してください!あなたの長さのプレフィックスは4バイトである場合は、2つのバイトを読み、次の2を欠場したくない...)

+0

うーん、 contentLengthをヘッダーに追加します。ありがとうございます。私はprocessPacket()でバイナリリーダーを使用していますが、明らかに、部分的なパケットしか渡されていないときには恐ろしいことに失敗しています。 – Endian

+0

@Endian:パケットの代わりにネットワークストリームを渡すのはなぜですか? –

+0

@Jon:私のbinaryReaderがバッファアンダーランを取得せずに読むことができるチャンクという意味で、パケットをもっとたくさん。私は元の投稿を編集しました。あなたの提案とそれがうまくいっているように見えるので、助けてくれてありがとうございます。 :) – Endian

関連する問題