提升Asio,多线程和多个io_service

时间:2015-11-04 18:20:16

标签: c++ multithreading boost-asio

我想开发一个服务器使用多个线程和多个io_service实例(每个线程使用一个io_service实例)来监听端口。对于每个io_service实例,我创建了一个相应的boost :: asio :: ip :: tcp :: acceptor对象。我试试这段代码:

 using namespace boost::asio;
    ...
    io_service io_service_;
    io_service io_service_1;

    ip::tcp::acceptor* acceptor_;
    acceptor_ = new ip::tcp::acceptor(io_service_);
    ip::tcp::endpoint ep( ip::tcp::v4(), LISTEN_PORT);
    acceptor_->open(ep.protocol());
    acceptor_->bind(ep);
    acceptor_->listen();

    ip::tcp::acceptor* acceptor_1;
    acceptor_1 = new ip::tcp::acceptor(io_service_1);
    acceptor_1->open(ep.protocol());
    acceptor_1->bind(ep);
    acceptor_1->listen();
    ...

    boost::thread th( boost::bind(&io_service::run, &io_service_));
    boost::thread th( boost::bind(&io_service::run, &io_service_1));
    ...
运行时

将显示错误对话框:

  

升压:: exception_detail :: clone_impl< boost :: exception_detail :: error_info_injector>在内存位置0x001FF704。

你能帮助我如何制作一个多线程服务器,每个线程都使用一个io_service实例吗?

更新:正如我在Boost.Asio C ++网络编程中所读到的那样,有3种方法可以将io_service与线程一起使用:

  1. 带有一个io_service和一个处理程序线程的单线程(运行io_service :: run()的线程)
  2. 使用单个io_service实例和多个实例进行多线程处理 处理程序线程
  3. 多线程,包含多个io_service实例和多个线程
  4. 我可以实现案例1和2.但是对于案例3,我不知道如何实现它来处理许多并发连接,我应该使用1个线程来处理1个io_service(如上所述)?案例3是否具有比案例2更好的性能(可以处理更多并发连接)?

2 个答案:

答案 0 :(得分:5)

您可以使用多个线程,但需要使用1个接收器作为端口。

IO服务是线程安全的,因此您可以在许多线程上使用一个服务。

您甚至可以拥有多个io服务,没问题。您不能将多个接收器绑定到同一个端口(除非您绑定到不同的逻辑网络接口,但是,那不是真正“相同的端口”)。

#include <boost/asio.hpp>
#include <boost/thread.hpp>

using namespace boost::asio;
using namespace boost;

int main() {
    io_service io_service_;

    ip::tcp::acceptor acceptor_(io_service_, { {}, 6767 });
    acceptor_.bind({ ip::tcp::v4(), 6767 });

    boost::thread_group tg;
    for (unsigned i = 0; i < thread::hardware_concurrency(); ++i)
        tg.create_thread(boost::bind(&io_service::run, &io_service_));

    // ...
    //
    tg.join_all();
}

答案 1 :(得分:3)

您只能在给定端口上监听一个acceptor。如果您想使用一个端口处理多个客户端,则需要在acceptor上设置选项reuse_address。这样,传递给async_accept()的套接字将使用不同的端口,让您的侦听端口可以自由接受来自其他客户端的连接。

boost::asio::io_service ios_;
boost::asio::ip::tcp::acceptor acceptor_(ios_);

void handle_client(boost::shared_pointer<boost::asio::ip::tcp::socket> sock);
void start_accept();

int main() {
    boost::asio::ip::tcp::endpoint ep(ip::tcp::v4(), LISTEN_PORT);
    acceptor_.open(ep.protocol());
    acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
    acceptor_.bind(ep);
    acceptor_.listen();
    boost::thread_group threads;
    for (int i = 0; i < NUM_WORKER_THREADS; ++i) {
        threads.create_thread(boost::bind(&io_service::run, &ios_));
    }
    start_accept();
    threads.join_all();
}

void start_accept() {
    boost::shared_pointer<boost::asio::ip::tcp::socket> sock(ios_);
    acceptor_.async_accept(*sock, boost::bind(handle_client, sock));
}

void handle_client(boost::shared_pointer<boost::asio::ip::tcp::socket> sock) {
    start_accept();
    // talk to the client
}

有关更完整的示例,请参阅Boost's HTTP server example