等待与请求序列号匹配的响应

时间:2012-08-09 23:53:20

标签: c# asynchronous async-await

我正在尝试实现一个网络应用协议客户端库,由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,或者我已经完全错了。

希望我的问题足够明确。

由于

1 个答案:

答案 0 :(得分: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);
}