2

TCP 接続を介したバイナリ要求/応答で構成されるネットワーク アプリケーション プロトコル クライアント ライブラリを実装しようとしています。このクライアントを、c#5 の async/await コンストラクトに依存して完全に非同期にしたいと考えています。

NetworkStream で送信される各リクエストには、関連付けられた適用可能なシーケンス番号が含まれています。要求に対する応答では、応答が元の要求と一致するように、同じシーケンス番号を指定する必要があります。リクエスト R1 を発行すると、もちろん、R1 への応答は将来のいつでも来る可能性があり、R1 への実際の応答の前に、他の要求に対する他の応答が送信される可能性があります。

ライブラリのクライアント コードでやりたいことは、次のような単純で愚かなことです。

var resp = await SendSomeRequestAsync(req);

SendSomeRequestAsync は、(SendSomeRequestAsync で) などのように、回線上で非同期に要求を送信し (その部分は正しい)、関連する応答 (要求で送信されたシーケンス番号と一致する) を何らかの方法で待ちます。

var dummy = await _ns.WriteAsync(rawBytes, 0, rawBytes.Length); // _ns is a NetworkStream
var resp = await GetResponseMatchingSequenceNumberAsync(sequenceNumber);

クライアントが接続で着信応答を非同期に読み取っている接続を開始するときに起動されるループがあります。

 while (true)
 {
    Response rsp = await ReadNextResponseAsync(_ns);
    DispatchReceivedResponse(rsp);
 }

GetResponseMatchingSequenceNumberAsync を実装する方法がわかりません。または、すでに完全に間違っているかどうかもわかりません。

私の質問が十分に明確であることを願っています。

ありがとう

4

1 に答える 1

3

私はまさにこの問題に遭遇しましたが、以下はかなりきれいに見えました:

を作成し、その中にインスタンスIDictionary<int,Response>を格納します。TaskCompletionSource<Response>応答が返ってきたら、TaskCompletionSource を見つけて完了に設定します。このコードのスレッド セーフについては主張しません。ディクショナリはおそらく並行型であるか、少なくとも何らかのロックでアクセスする必要があります。

public Task<Response> GetResponseMatchingSequenceNumberAsync(sequenceNumber)
{
   var tcs=new TaskCompletionSource<Response>();
   pendingTasksDictionary.Add(sequenceNumber,tcs);
   return tcs.Task;
}

private void ResponseHandler(int sequenceNumber,Response response)
{
   var pendingTcs=pendingTasksDictionary[sequenceNumber];
   //remove from dictionary
   pendingTcs.SetCompleted(response);
}
于 2012-08-10T00:07:49.657 に答える