我正在尝试编写符合RFC 2812标准的C ++ IRC库。 我在设计客户端时遇到了一些麻烦。 根据我的阅读,IRC通信往往是异步的。
我正在使用boost::asio::async_read
和boost::asio::async_write
。
通过阅读我收集的文档,您可以在完成之前执行多个async_write请求。因此,您最终会得到相当嵌套的回调。这不是打败异步调用的目的吗?使用同步调用防止嵌套不是更好吗?如果没有,为什么?
其次,如果我没有弄错的话,每个boost::asio::async_write
都应该跟boost::asio::async_read
跟进,以接收服务器对发送的命令的响应。因此,我的客户端函数需要接受一个回调参数,以便该类用户可以在客户端收到响应后执行某些操作(例如发送另一条消息...)。
如果我要继续使用异步执行此操作,我应该保留std::deque<std::tuple<message, callback>>
并且每次boost::asio::async_write
完成,并且队列中有一个元组,出列并发送消息然后提高回调?这是实现这个系统的最佳方式吗?
我一直在思考,因为消息一直被发送,我将不得不实现某种类型的侦听器循环来排队响应,但是如何将这些响应与触发它们的特定命令相关联?或者,如果响应只是来自其他用户的频道消息?
答案 0 :(得分:2)
IRC协议是全双工协议。因此,应始终监听服务器连接,期望命令处理。可以认为,主要应该使用从服务器接收的消息来更新状态,而不是关联请求和响应,因为服务器可能不响应命令或者可能比预期更晚响应。例如,可以发出WHOIS
命令,但在收到对PRIVMSG
的响应之前会收到多个WHOIS
命令。对于聊天客户端,用户可能希望在等待WHOIS
的响应时能够接收聊天消息。因此,拥有async_write()
到async_read()
的调用链在处理协议时可能并不理想。
对于给定的套接字,如果存在未完成的组合读取操作,并且如果存在未完成的组合写入操作,则Asio文档建议不启动其他读取操作。排队消息并从队列中进行异步调用链处理是实现此建议的好方法。考虑使用队列和异步调用链读取此answer以获得一个很好的解决方案。
另外,请注意,即使在活动连接上,服务器也可能发送PING
命令。当客户端使用PONG
命令进行响应时,可能需要在出站队列的前面插入PONG
命令,以便尽快将其发送出去。
答案 1 :(得分:1)
这是不是打败了进行异步调用的目的?
通常的解决方案是使用股线:
Why do I need strand per connection when using boost::asio?
您可以使用(隐式)strand¹在同一个io对象上排队多个异步操作。
使用strand确保在相同的逻辑线程上调用完成处理程序。
在发送下一个命令之前,您确实可以保留命令队列并等待每个命令的响应。
如果您可以通过不同的类型回复来发现相关性,那么您可能会更聪明一些,但是您需要按类型保留队列命令我认为过早优化。