我有一个通过TCP运行的请求/响应协议,我想为其提供async / await API。该协议是STOMP,这是一个相当简单的基于文本的协议,可以通过TCP或SSL运行。在STOMP中,客户端发送六个左右的命令帧之一,并在命令的标题中指定receipt
ID。服务器将使用RECEIPT
或ERROR
帧进行响应,并使用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()
,有没有人知道它是如何运作的?
答案 0 :(得分:2)
HttpClient
要简单得多,因为HTTP每个请求只有一个响应。在HTTP中没有未经请求的服务器消息。
要正确设置此类事件的“流”,最好使用TPL Dataflow或Rx。否则,您必须创建一个无界接收缓冲区并重复执行异步ReceiveMessage调用。
所以我建议使用TPL Dataflow管道来创建“消息”的源块,然后将一些与请求匹配(使用TaskCompletionSource
通知发送者它已完成)并公开其余部分({ {1}}帧)作为源块。
在内部,您的处理管道如下所示:
MESSAGE
- > BeginReceive
用于邮件框架 - >
TransformBlock
将响应消息与请求进行匹配。ActionBlock
代表BufferBlock
个框架。