0

私はコードを持っていました(単純なチャットアプリケーションを想定しましょう)、同期でTcpを使用しました。しかし、セットアップは難しいですが、非同期の方法の方がまったく優れているため、同期から非同期に方法を変更することにしました。しかし今、私は非同期を使用していくつかの問題に直面しています。

  1. バッファサイズ:ピアからバイトを取得するには、限られたサイズのバイトを考慮する必要があることを私は知っています。私は多くの記事を読みましたが、私の問題は解決していません。これに対処するための非常に単純ですが価値のないアプローチがあり、各メッセージの最後に文字を付けています。そうすれば、受信者はメッセージが完全に受信されたことを理解できます。しかし、私には別の問題があり、それが私にとって抱えている別の問題に対してこのアプローチをさらに実行することを妨げています。

次のコードで私の問題を説明しましょう:

public void Send(byte[] message, Socket connection)
{
    connection.BeginSend(message, 
                         0, 
                         message.Length, 
                         SocketFlags.None, 
                         new AsyncCallback(OnSend), 
                         connection);
}

OnSendメソッドでは、connection.EndSend(result)を使用します。ここで、resultはIAsyncResultです。しかし、次のコードのようにSendメソッドを2回呼び出すと、OnReceiveコールバックは両方を1つのメッセージとして受信します。

Send(Encoding.Unicode.GetBytes("Hello"));
Send(Encoding.Unicode.GetBytes("Bye"));

私のOnReceiveMethodはConsole.WriteLine(message);を使用します。ここで、messageはピアから受信した文字列です。同期方法を使用した出力は、

こんにちは

さよなら

しかし、非同期的に私はそれを2つではなく1つのメッセージとして受け取るので、印刷されます

こんにちはさようなら

よろしくお願いいたします。PeymanMortazavi

4

2 に答える 2

4

この問題を克服するために、単純に同期ソケットに切り替えることに私はあまり同意できません。はるかに優れたアプローチは、Queue<string>(たとえば)送信時にメッセージを入れる場所を使用することです。

次に、非同期ソケットにこのキューからパケットをデキューさせ、キューが空になるまで、現在のパケットの送信が完了したら次のパケットを送信します。

次に、キューにメッセージが再び存在するまで、BeginSend を再度呼び出さないことを選択できます。

于 2012-12-14T12:38:28.817 に答える
2

同期呼び出しを使用すると、2 番目のメッセージを送信する前に、最初のメッセージが完全に送信されることが保証されます。ただし、非同期メソッドを使用すると、2 つのメッセージを発信キューに追加して、送信を待機するだけです。たまたま適切なタイミングでヒットした場合、2 つの別々のメッセージとして送信される可能性がありますが、両方を非常に高速に追加するため、両方を一緒に送信する可能性が高くなります。TCP/IP ソケット通信を単一の進行中のデータ ストリームと考えると、はるかにうまくいくでしょう。メッセージの開始位置と終了位置を判別できるように、メッセージをフォーマットする必要があります。ソケットを介してデータを受信する場合、(データのフォーマットに基づいて) 完全なメッセージを受信したと判断するまで、受信したメッセージをバッファーに追加し続ける必要があります。ソケットからの各読み取りが単一の完全なメッセージであることに依存するべきではありません。部分的なメッセージまたは複数のメッセージでさえある可能性があることを期待する必要があります。

于 2012-05-17T13:55:04.610 に答える