创建包装请求/响应协议的async / await API

时间:2013-02-13 23:33:43

标签: c# .net .net-4.5

我有一个通过TCP运行的请求/响应协议,我想为其提供async / await API。该协议是STOMP,这是一个相当简单的基于文本的协议,可以通过TCP或SSL运行。在STOMP中,客户端发送六个左右的命令帧之一,并在命令的标题中指定receipt ID。服务器将使用RECEIPTERROR帧进行响应,并使用receipt-id字段,以便客户端可以将响应与原始请求进行匹配。服务器还可以随时发送MESSAGE帧(STOMP基本上是一种消息传递协议),不包含receipt-id

要允许多个未完成的请求并处理任何MESSAGE个框架,该计划应始终保持Socket.BeginReceive()个未完成状态。所以我想的是最简单的实现是创建一个可等待的事件(如互斥体),将该事件存储在一个表中,将带有receipt设置的命令请求发送到表中,并且封锁事件。当socket.BeginReceive()触发时,函数可以从消息中获取receipt-id,查找表中的事件并发出信号(并存储某些状态,如成功或错误)。这将唤醒调用函数,该函数可以查看结果并将成功或失败返回给调用应用程序。

这听起来基本正确吗?我之前使用过async / await API但从未编写过我自己的API。如果可以,我应该使用什么样的等待事件?一个简单的Monitor.Wait()会阻止但不是我想要的方式,对吗?如果我将Task.Run()中的所有内容包裹起来,那么Monitor.Wait()的行为是否合适?或者是否有我应该使用的新同步构造?我基本上是在实施HttpClient.GetAsync(),有没有人知道它是如何运作的?

1 个答案:

答案 0 :(得分:2)

HttpClient要简单得多,因为HTTP每个请求只有一个响应。在HTTP中没有未经请求的服务器消息。

要正确设置此类事件的“流”,最好使用TPL DataflowRx。否则,您必须创建一个无界接收缓冲区并重复执行异步ReceiveMessage调用。

所以我建议使用TPL Dataflow管道来创建“消息”的源块,然后将一些与请求匹配(使用TaskCompletionSource通知发送者它已完成)并公开其余部分({ {1}}帧)作为源块。

在内部,您的处理管道如下所示:

  • 重复MESSAGE - >
  • BeginReceive用于邮件框架 - >
    • TransformBlock将响应消息与请求进行匹配。
    • ActionBlock代表BufferBlock个框架。