2

C# で非同期ソケットを作成しようとしています。私は多くの msdn 記事を読んで、次の 2 つの例を見つけました: serverclient

これを使用して独自の非同期ソケットを実装するサンプル コードを理解しました。この例では、サーバーはチェックを行っ<EOF>てストリームの終わりを判断し、応答を送信します。ストリームが終了したときに特別なリテラルをチェックせずに知りたいです。私の考えは、再帰的にチェック(bytesRead > 0)して呼び出すことでした。handler.BeginReceive()以下を参照してください。

オリジナル

if (bytesRead > 0) {
    // There  might be more data, so store the data received so far.
    state.sb.Append(Encoding.ASCII.GetString(
        state.buffer,0,bytesRead));

    // Check for end-of-file tag. If it is not there, read 
    // more data.
    content = state.sb.ToString();
    if (content.IndexOf("<EOF>") > -1) {
        // All the data has been read from the 
        // client. Display it on the console.
        Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
            content.Length, content );
        // Echo the data back to the client.
        Send(handler, content);
    } else {
        // Not all data received. Get more.
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReadCallback), state);
    }
}

私の考え

if (received > 0)
{
    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, received));
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
else
    Send(handler, state.sb.ToString());

元のパーツを自分のパーツに置き換えると、プログラムの実行が停止します。EndSend()クライアントがin で実行し、 inの後にSendCallback()スレッドをブロックすると思います。どうすればこれを渡すことができますか?ストリームの終了を決定するトークンを使用する必要がありますか?receiveDone.WaitOne()StartClient()

他に良いサンプルコードはありますか? たった今見つけた二人。

(証拠。サーバーはオンライン クライアントを受信し、このバッファーから循環バッファーに入れ、マルチスレッドでレコードを読み取って処理する必要があります。)

編集

私がフォリングを使用する場合:

if (receive > 0)
    state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, receive));
if (receive == StateObject.BufferSize)
    state.listener.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
else
    Send(state.listener, state.sb.ToString());

すべてが正常に機能していると思います。大丈夫ですか?それとも何かが恋しいですか?

2つのifを組み合わせると、再び機能しなくなります。なんで?

if(receive > 0 || receive == StateObject.BufferSize)->if(receive > 0) // Not working.

4

2 に答える 2

4

コードのバージョンの問題は、BeginReceive常に開始することですが、0バイトが受信されたときなど、1 つの状況で開始されます。実際、送信の終了は、ほとんどの場合、0 以外でバッファ サイズより小さいデータ量を受信した場合に発生します (場合によっては、バッファ サイズとまったく同じ場合もあります)。0バイトの受信は発生しません。これは、送信の終了ではなく送信がないことを意味するためです。これは、送信者が接続を閉じて送信を終了すると仮定しています。

送信の終了を示す方法はいくつかあります。

  • 送信者が接続を閉じる
  • 特別なシーケンスが送信されます (EOF など)
  • 受信者は彼が期待したものを受け取りました(最初にヘッダーを取得したため)

最初のアプローチの問題は、通常、接続を閉じる (および再度開く) とコストがかかることです。ヘッダーの問題は、(何らかのネットワークの問題が原因で) ヘッダーを見逃すと失われることです。現在のデータ パケットがいつ終了するかがわからないため (ヘッダーが失われる)、次のヘッダーがいつ来るかわかりません。問題が発生した場合の最も簡単な回復は、何らかの形で EOF を提供します。文字通り<EOF>文字列である必要はありません。通常のデータ ストリームでは (ほとんどの場合) 発生しないものであれば何でもかまいません。

EOFそうは言っても、ヘッダーとヘッダーの組み合わせ、またはレコードの開始を示す特別なシーケンスを含むヘッダーの使用を妨げるものは何もありません。

于 2013-04-04T10:45:57.253 に答える
0

ネットワーク ストリームが終了したと判断できる状況は、リモート エンドが接続を正常にシャットダウンしたときです。これにより、EndRead戻り値がゼロになります。もちろん、リモート エンドにデータを送り返したい場合、これは最適な方法ではありません。基本的に、最初の接続を再利用するのではなく、クライアントへの新しい接続を作成する必要があります。これは確かに実行できますが、クライアントが NAT ルーターの背後にある場合など、通常はうまく機能しません。

サンプル コードがチェックするときに行うことEOFは、アプリケーション レベルのプロトコルを適用することです。基盤となるネットワーク スタックは、アプリケーションに配信するペイロードを理解していないため、概念的なストリームが終了したことを判断できません。これは、アプリケーションが責任を負うものです。タグまたはトークンをチェックすることは、それを行うための非常に簡単な方法です。

于 2013-04-03T16:51:38.537 に答える