为多个异步网络客户端操作提升asio

时间:2015-05-10 00:49:58

标签: c++ multithreading boost-asio

我想使用boost :: asio(或asio独立)通过异步套接字每分钟一次查询多个网络设备。对于测试,我已经实现了一个Client类和一个控制台程序,它为一个设备执行该操作(不重复)。 像这样:

class MyClient
{
public:
    MyClient(asio::io_service& io_service);

    void GetData(CompletionHandler completionHandler);
}; 

MyClient :: GetData类在内部使用多个异步操作,其中每个操作的完成触发下一个操作,直到数据可用:

  • 连接
  • 阅读标题
  • 阅读数据
  • 断开

使用此类的控制台程序的工作方式如下:

int main(...)
{
    asio::io_service io_service_;

    MyClient c(io_service_, ...);
    ...
    c.GetData([](std::error_code ec, const FloatVector& values){
        //do something with values
    });

    io_service_.run();
    ...
}

现在我想在GUI程序中使用MyClient类,每分钟连接一次> 10个设备,但我仍然坚持整体设计。

首先,我创建了一个线程池,其中每个线程执行单个io_service实例的io_service :: run()。

现在,只要我的程序想要从设备读取数据,它就会在所有设备上循环,并且必须为每个设备创建一个MyClient实例并调用GetData()方法。

现在io_service :: run()是否在池的线程中执行,它如何与io_service一起工作?我可以简单地在GUI线程中调用MyClient :: GetData(),因为它在内部使用异步操作,或者我必须调用类似io_service :: post()的东西吗?

更新 我的代码和控制台演示大致遵循以下示例: www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/http/client/async_client.cpp

但是在GUI程序中,我不想在GUI线程中运行io_service.run()。现在假设我至少有一个执行io_service.run()的额外线程,并且用户按下应该启动设备读取的按钮。最终完成处理程序应将数据存储在数据库中,并向用户更新图形显示。

也许按钮处理程序可以简单地实例化MyClient并在其上调用GetData()并且一切正常,因为MyClient知道io_service并使用它f.e.在async_connect等

它是否像这样工作或者我在这里弄错了?

注意:此时我的问题不是如何处理完成处理程序中的数据!它是如何在多线程GUI程序中正确获取数据的。

2 个答案:

答案 0 :(得分:1)

请查看此示例www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/http/client/async_client.cpp。这应该有所帮助。

如果你看到handle_resolve是否成功,它会调用async_connect,这将导致handle_connect被触发。如果没有错误地调用handle_connect,它会将一些数据写入连接(async_write),然后调用async_read_until(没有错误)将触发handle_read_status_line,这可能会触发handle_read_headers,这可能触发handle_read_content。
如果您发现没有明确的断开连接,因为析构函数将在内部执行此操作。

答案 1 :(得分:1)

以下是您需要做的大致概述:

  • 首先请注意,如果没有工作要做,io_service.run()将立即返回。因此,根据您的工作流程,您可能需要推迟调用它,直到实际排队第一个异步连接为止。如果查看示例客户端,您将首先看到客户端被实例化,它将第一个操作排队(在这种情况下为异步解析),然后调用io_service.run()。
  • 因此,假设您正在按下按钮,此时您需要执行的操作是安排连接或解析,然后启动新线程并从该线程调用io_service.run()。
  • 一旦异步操作链完成并且您拥有了数据,您的处理程序将在您已经启动的新线程的上下文中被调用。这意味着您必须将消息发布回UI(因为通常UI工作只能在主线程上完成)。例如。你的示例中的lambda需要进行某种UI post消息操作(具体取决于我们在这里讨论的操作系统/ GUI)。
  • 然后您的GUI线程将接收该消息并更新您想要更新的任何UI状态(例如显示结果)