3

最初の4バイトでメッセージの長さインジケーターを指定するアプリケーションプロトコルを使用しています。Socket.Receiveは、その時点でプロトコルスタックにあるのと同じ量のデータを返すか、データが利用可能になるまでブロックします。これが、長さインジケーターでバイト数を受け取るまで、ソケットから継続的に読み取る必要がある理由です。反対側が接続を閉じた場合、Socket.Receiveは0を返します。私はそれをすべて理解しています。

読み取る必要のある最小バイト数はありますか?私が尋ねる理由は、ドキュメントから、socket.Receiveが戻ることができるときに全長インジケーター(4バイト)が使用できない可能性があるためです。その後、私たちは挑戦し続けなければならないでしょう。バッファの内外に物事をコピーする必要があるため、socket.receiveを呼び出す回数を最小限に抑える方が効率的です。したがって、長さインジケーターを取得するために一度に1バイトを取得する方が安全ですか、4バイトが常に使用可能であると想定するのが安全ですか、それともオフセット変数を使用して4バイトを取得しようとし続ける必要がありますか?

ある種のデフォルトの最小レベルがあるかもしれないと思う理由は、ソケットオプションで設定できるReceiveLowWater変数と呼ばれる変数に出くわしたためです。しかし、これはBSDにのみ当てはまるようです。MSDNSO_RCVLOWATを参照してください。

それはそれほど重要ではありませんが、私はユニットテストを書こうとしています。私はすでに標準の.Netソケットをインターフェースの後ろにラップしています。

4

2 に答える 2

7

4バイトが常に利用可能であると想定するのは安全ですか

いいえ。一度もない。誰かが、たとえばtelnetとキーボードを使用してプロトコルをテストしている場合はどうなりますか?または、実際の低速またはビジー接続を介して?一度に1バイトを受信すること、複数のReceive()呼び出しで分割された「長さインジケーター」を受信することもできます。これは単体テストの問題ではなく、特にストレスの多い状況で本番環境で問題を引き起こす基本的なソケットの問題です。

または、オフセット変数を使用して4バイトを取得しようとし続ける必要がありますか?

はい、そうすべきです。Socket.Receive()読みすぎないように、読み取るバイト数を指定できるオーバーロードを使用すると便利です。ただし、必要な値よりも少ない値を返す可能性があることに注意してください。これがoffsetパラメータの目的であるため、同じバッファに書き込みを続行できます。

byte[] lenBuf = new byte[4];
int offset = 0;

while (offset < lenBuf.Length)
{       
    int received = socket.Receive(lenBuf, offset, lenBuf.Length - offset, 0);

    offset += received;     

    if (received == 0)
    {
        // connection gracefully closed, do your thing to handle that
    }
}

// Here you're ready to parse lenBuf

ある種のデフォルトの最小レベルがあるかもしれないと思う理由は、ソケットオプションで設定できるReceiveLowWater変数と呼ばれる変数に出くわしたためです。しかし、これはBSDにのみ当てはまるようです。

正解です。「低水位を受け取る」フラグは下位互換性のためにのみ含まれており、MSDNのように、エラーをスローする以外は何もしませんSO_RCVLOWAT

このオプションは、Windows TCP/IPプロバイダーではサポートされていません。このオプションをWindowsVista以降で使用すると、getsockoptおよびsetsockopt関数がWSAEINVALで失敗します。以前のバージョンのWindowsでは、これらの関数はWSAENOPROTOOPT "で失敗します。したがって、オフセットを使用する必要があると思います。

パフォーマンスを向上させることができるので、それは残念です。ただし、@ cdleonardがコメントで指摘しているように、通常は一度に4バイトを受け取るため、オフセット変数を保持することによるパフォーマンスの低下は最小限に抑えられます。

于 2012-10-30T08:48:37.880 に答える
2

いいえ、最小バッファ サイズはありません。受信の長さは実際のスペースと一致する必要があります。

メッセージの実際のデータの前に 4 バイトの長さを送信する場合、受信者は 1、2、3、または 4 バイトが返されるケースを処理し、4 バイトすべてが受信されるまで読み取りを繰り返し続け、受信する手順を繰り返す必要があります。実際のデータ。

于 2012-10-26T21:06:25.263 に答える