1

私たちのサーバーは一見パケットベースです。これは、古いシリアルベースのシステムからの適応です。何年にもわたって追加、変更、再構築などが行われてきました。TCPはストリームプロトコルであり、パケットプロトコルではないため、パケットが分割されることがあります。ServerSocketは、クライアントがデータを送信するときに、データの一部に。などのメッセージのサイズが含まれるように設計されています55。これらのパケットは複数の部分に分割されることがあります。それらは順番に到着しますが、メッセージがどのように分割されるかわからないため、サーバーが分割されたメッセージを識別する方法を知らない場合があります。

だから、あなたに背景情報を与えました。パケットが分割されている場合、パケットが入ってくるときにパケットを再構築するための最良の方法は何ですか?私たちはC++Builder 5を使用しています(そうです、古いIDEですが、現時点で使用できるのはこれだけです。.NET以降のテクノロジで再設計するための多くの作業があります)。

4

3 に答える 3

5

TCPデータが送信されたのと同じ順序で到着することを保証します。

そうは言っても、すべての受信データをバッファに追加するだけです。次に、バッファに 1 つ以上のパケットが含まれているかどうかを確認し、それらをバッファから削除します。残りのデータはすべて、将来のチェックのためにバッファに保持します。

もちろん、これは、次のデータのサイズを示すヘッダーがパケットにあると仮定します。

パケットが次の構造を持っていると考えてみましょう:

[LEN] X X X...

はデータLENのサイズで、各 X はバイトです。

受け取った場合:

4 X X X
[--1--]

パケットは完全ではありません。バッファに残しておくことができます。次に、他のデータが到着したら、それをバッファに追加するだけです:

4 X X X X 3 X X X
        [---2---]

これで、簡単に解析できる 2 つの完全なメッセージが得られます。

その場合は、ホストに依存しない形式で長さを送信することを忘れないでください (ntohsおよびntohl役立つ場合があります)。

于 2010-10-02T21:10:13.593 に答える
1

readBytes という関数か、バッファと長さパラメータを取り、そのバイト数が読み取られるまで読み取る関数を用意します。実際に読み取られたバイト数をキャプチャする必要があります。それが期待する数よりも少ない場合は、バッファー ポインターを進めて残りを読み取ります。それらをすべて読むまでループを続けます。

次に、ヘッダーが固定長であると仮定して、ヘッダー (長さを含む) に対してこの関数を 1 回呼び出します。実際のデータの長さを取得したら、この関数を再度呼び出します。

于 2010-10-02T21:11:13.217 に答える
1

これは、多くの場合、メッセージの前に 1 バイトまたは 2 バイトの長さの値を付けることで実現されます。これは、あなたが言ったように、残りのデータの長さを示します。私の理解が正しければ、これはプレーン テキスト (つまり、「5」、「5」) として送信されており、分割される可能性があります。10 進数の長さがわからないため、ややあいまいです。どうしてもプレーン テキストを使用する必要がある場合は、長さを 16 ビットの 16 進数値としてエンコードできます。つまり、次のようになります。

00ff <255バイトデータ> 000a <10バイトデータ>

このように、サイズ ヘッダーの長さは 4 バイトに固定され、ソケットで受信するときに最小読み取り長として使用できます。


編集:おそらく私は誤解しました-長さの値を読み取ることが問題にならない場合は、受信データを文字列、バイトバッファー、またはその長さが最初に読み取った値と等しくなるまで連結することにより、分割に対処します。残りは TCP が処理します。

クライアントが完全なメッセージを送信しない場合に、ブロック読み取り状態でスタックしないように、特別な予防措置を講じてください。たとえば、長さヘッダーを受け取り、バッファーがいっぱいになるまで recv() 呼び出しをブロックして読み取り続けるループを開始するとします。悪意のあるクライアントが意図的にデータの送信を停止した場合、クライアントが切断するか送信を開始するまで、サーバーがロックされる可能性があります。

于 2010-10-02T21:14:33.947 に答える