0

カスタマイズしたプロトコルに従って、ポートをリッスンしていくつかのパケットを受信するアプリケーションを作成しました。パケットは49バイトから1500バイトのいずれかであり、パケットのデータ長からわかります。49バイトのパケットとそれより大きいパケットのデータを解釈して処理する方法は異なります。

問題は、1374バイト未満のパケットを受信するとすべて問題がないことですが、パケット長が長くなると、次の例外が発生し、データの最後の4バイトも失われます(1384バイトのパケットでテストしました。最後の4バイトを失った)

発生する例外:インデックスが範囲外でした。負ではなく、コレクションのサイズよりも小さい必要があります。パラメータ名:startIndex

49バイトの各パケットには35バイトのデータがあり、より大きなパケットのデータ長は非決定論的です(圧縮のため)。

最後の4バイトが別々の「bytes」変数と「result」変数にあることがあります。これは、それらが新しいパケットのように扱われ、それらが属するパケットに添付されていないことを意味します。

データを受信するためのコードは次のとおりです。

TcpClient Client = obj as TcpClient;
        EndPoint ep = Client.Client.RemoteEndPoint;
        List<Byte> result = new List<byte>();
        result.Capacity = 2000;
        try
        {


            NetworkStream stream = Client.GetStream();
            int i = 49;
            while ((i = stream.Read(bytes, 0,49)) != 0)
            {

                for (int id = 0; id < i; id++)
                {
                    result.Add(bytes[id]);
                }
//reading data length to determine packet length
                byte[] tmp = new byte[2];
                tmp = BitConverter.GetBytes(BitConverter.ToUInt16(result.ToArray(), 9));
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tmp);
                }
                Int16 l = BitConverter.ToInt16(tmp, 0);
                if (l>35)
                {
                    stream.Read(bytes, result.Count, l - 35);
                    for (int id = 49; id <((l-35)+49); id++)
                    {
                        result.Add(bytes[id]);
                    }
                    if (this.TCPDataReceivedHandler != null)
                    {
                        this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
                        result.Clear();
                        Array.Clear(bytes, 0, 2000);
                        result.Capacity = 2000;
                    }
                }
                else
                {
                    if (this.TCPDataReceivedHandler != null)
                    {
                        this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
                        result.Clear();
                        Array.Clear(bytes, 0, 2000);
                        result.Capacity = 2000;
                    }
                }


            }
            System.Diagnostics.Debug.WriteLine("client Close");
            Client.Close();

        }
        catch (System.Exception ex)
        {
            throw ex;
        }
        finally
        {
            Client.Close();
            this.clients.Remove(Client);
        }

グレッグサジェストと私の研究によると、私も次の方法を使ってみました:

NetworkStream stream = Client.GetStream();
            int bytesread = 0, OffsetTemp = 0;

            while (stream.CanRead)
            {
                OffsetTemp = 0;

                bytesread += stream.Read(bytess, OffsetTemp, 11);
                OffsetTemp = OffsetTemp + 11;



                byte[] tmp = new byte[2];
                tmp = BitConverter.GetBytes(BitConverter.ToUInt16(bytess.ToArray(), 9));
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tmp);
                }
                Int16 l = BitConverter.ToInt16(tmp, 0);

                bytesread += stream.Read(bytess, OffsetTemp++, 11 + l + 3);
                for (int id = 0; id < l + 14; id++)
                {
                    result.Add(bytess[id]);
                }

                if (this.TCPDataReceivedHandler != null)
                {
                    this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
                    result.Clear();
                    Array.Clear(bytess, 0, 2000);
                }

            }
4

1 に答える 1

0

TCPを使用する場合、入力するデータブロックのサイズは、受信側で取得するデータブロックのサイズと同じであるとは限らないことに注意する必要があります。TCPはストリームプロトコルであるため、同じバイトが送信されたのと同じ順序で反対側に到達することが保証されます(そうでない場合、ソケット接続はリセットされます)。TCPは、への呼び出し間にいかなる種類のブロック境界も維持せずsend()、ネットワークの状態に応じて、ブロックを任意に分割または合体させることができます。

受信者は、への呼び出しからのデータの受信を処理できるように準備する必要がありstream.Read()ますが、コードはこれを実行していないようです。たとえば、正しく記述されたレシーバーコードは、一度に1バイトstream.Read()しか受信しない場合でも、引き続き正しく機能する必要があります。

于 2012-10-14T18:53:06.867 に答える