12

我有我的应用程序,其中侦听和处理来自 Internet 套接字和 unix 域套接字的消息。现在我需要将 SSL 添加到 Internet 套接字,我对应用程序中的所有套接字使用单个io_service对象。现在看来我需要io_service为网络套接字和 unix 域套接字添加单独的对象。我的应用程序中没有任何线程,我使用async_sendandasync_recieveasync_accept处理数据和连接。请指出任何使用io_service带有异步处理程序的多个对象的示例。

4

2 回答 2

37

这个问题有一定程度的不确定性,好像io_service需要多个对象。我在参考文档或要求单独对象的SSLUNIX 域套接字的概述中找不到任何内容。io_service无论如何,这里有几个选项:


单人io_service

尝试使用单个io_service.

如果您没有io_service对象的直接句柄,但您有 Boost.Asio I/O 对象(例如套接字)的句柄,则io_service可以通过调用socket.get_io_service().


每使用一个线程io_service

如果需要多个io_service对象,则为每个对象分配一个线程io_service。这种方法用于 Boost.Asio 的HTTP Server 2示例。

boost::asio::io_service service1;
boost::asio::io_service service2;

boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();

这种方法的一个结果是它可能需要应用程序做出线程安全保证。例如,如果service1service2两者都有调用的完成处理程序message_processor.process(),则message_processor.process()需要是线程安全的或以线程安全的方式调用。


民意调查io_service

io_service提供非阻塞替代run(). io_service::run()在所有工作完成之前as 将阻塞的位置,io_service::poll()将运行准备好运行且不会阻塞的处理程序。这允许单个线程在多个io_service对象上执行事件循环:

while (!service1.stopped() &&
       !service2.stopped())
{
  std::size_t ran = 0;
  ran += service1.poll();
  ran += service2.poll();
  // If no handlers ran, then sleep.
  if (0 == ran)
  {
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
  }
}

为了防止在没有准备好运行的处理程序时出现繁忙的循环,可能值得在睡眠中添加。请注意,这种睡眠可能会在事件的整体处理中引入延迟。


将处理程序转移到单个io_service

一种有趣的方法是使用 astrand将完成处理程序转移到单个io_service. 这允许每个线程io_service,同时避免需要让应用程序做出线程安全保证,因为所有完成处理程序都将通过单个服务发布,其事件循环仅由单个线程处理。

boost::asio::io_service service1;
boost::asio::io_service service2;

// strand2 will be used by service2 to post handlers to service1.
boost::asio::strand strand2(service1);
boost::asio::io_service::work work2(service2);

socket.async_read_some(buffer, strand2.wrap(read_some_handler));

boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();

这种方法确实有一些后果:

  • 它需要打算由 main 运行的处理程序io_service通过strand::wrap().
  • 异步链现在通过两个io_services,创建了一个额外的复杂级别。重要的是要考虑辅助io_service节点不再有工作导致其run()返回的情况。

异步链通常出现在同一个io_service. 因此,服务永远不会耗尽工作,因为完成处理程序会将额外的工作发布到io_service.

   |    .------------------------------------------.
   V    V                                          |
read_some_handler()                                |
{                                                  |
  socket.async_read_some(..., read_some_handler) --'
}

另一方面,当一个 strand 用于将工作转移到另一个 strand 时io_service,包装的处理程序在 内部调用service2,导致它将完成处理程序发布到service1. 如果包装的处理程序是 中唯一的工作service2,则service2不再有工作,导致servce2.run()返回。

    service1                      service2
====================================================

        .----------------- wrapped(read_some_handler)
        |                            .
        V                            .
 read_some_handler                NO WORK
        |                            .
        |                            .
        '----------------> wrapped(read_some_handler)

为了解决这个问题,示例代码使用了io_service::workfor ,service2因此run()在明确告知 to 之前一直处于阻塞状态stop()

于 2013-03-19T17:59:47.170 回答
1

看起来您正在编写服务器而不是客户端。不知道这是否有帮助,但我正在使用 ASIO 从我的客户端与 6 个服务器进行通信。它使用 TCP/IP SSL/TSL。您可以在此处找到代码的链接

您应该能够将一个 io_service 对象与多个套接字对象一起使用。但是,如果您决定确实想要拥有多个 io_service 对象,那么这样做应该相当容易。在我的课堂上,io_service 对象是静态的。因此,只需删除 static 关键字以及构造函数中仅创建一个 io_service 对象实例的逻辑。根据您的服务器预期的连接数,您最好使用专用于处理套接字 I/O 的线程池,而不是为每个新的套接字连接创建一个线程。

于 2013-03-19T16:13:10.127 回答