c++ - Boost.Asio、tcp::iostream 和多线程

标签 c++ multithreading boost-asio

tl;dr

如何使基于 tcp::iostream 的服务器(如以下代码所示)在单独的线程中接受多个连接?


我正在尝试使用 Boost.Asio 为一个预先存在的库实现一个服务器/客户端接口(interface),摸索着 examples . (是的,C++11 之前的版本。请耐心等待。)

使用 tcp::iostream 的理由。

由于情况,整个服务器进程是可选的;即,当使用 port = 0 调用客户端时,它会将请求传递给本地 Handler 实例。在所有其他情况下,它连接到希望监听该端口号的服务器,然后服务器将请求传递给服务器进程的 Handler 实例。

(这完全是 127.0.0.1。服务器存在是因为多个 Handler 实例之间存在重要的共享状态,所以如果所有用户都将他们的请求发送到机器上运行的一台服务器,它在内存和启动时间上会容易得多。存在“本地”、port = 0 选项是因为这样我就可以只使用一个客户端可执行文件用于基于服务器的和本地的使用。 )

无论如何。有 boost::asio::ip::tcp::iostream ,这让事情变得非常简单:

boost::asio::io_service io_service;

boost::asio::ip::tcp::endpoint endpoint( boost::asio::ip::tcp::v4(), port_ );
boost::asio::ip::tcp::acceptor acceptor( io_service, endpoint );

for (;;)
{
    boost::asio::ip::tcp::iostream stream;
    boost::system::error_code ec;
    acceptor.accept( *stream.rdbuf(), ec );
    if ( ! ec )
    {
        Handler( stream, stream ).run(); // <---- This is the "why"
    }
    else
    {
        throw ec.message();
    }
    stream.close();
}

你知道这是怎么回事。 Handler 类接受一个输入流和一个输出流。除了传递 tcp::iostream,我还可以传递 std::cin/std::cout 或一些 std::fstream 指向一个请求文件和一个日志文件。这对我来说非常有效。

最大的“但是”

问题是上面的代码是严格单线程的。由于 Handler 完成的工作需要大量时间(分钟),因此我需要多个工作线程。

以及关于“如何使 Boost.Asio 多线程化”的所有示例和教程——例如HTTP 示例 server2 (使用单个 io_service 对象的池)和 server3 (使用多个线程,每个线程都调用 io_service::run())——采用完全不同的方式(acceptor::async_accept()tcp 上工作: :socket 对象包含在单独的 connection 对象中)。

要么归咎于我对 Boost.Asio 的整体架构的困惑,要么是缺乏文档,但我无法弄清楚如何将这两种方法结合起来,即有多个工作线程,每个线程都将其连接作为一个 来处理tcp::iostream。似乎没有办法从 tcp::iostream 检索一个 tcp::socket,也没有办法向它提供一个,在这一点上我有点难过.

最佳答案

我想我巧妙地错过了这里的问题。没有看到与 Asio 相关的内容:

Live C++03 On Coliru

#define BOOST_THREAD_USES_MOVE
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <boost/asio.hpp>
#include <boost/asio/basic_socket_iostream.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <list>

struct Handler {
    std::istream& is;
    std::ostream& os;

    Handler(std::istream& is, std::ostream& os) : is(is), os(os){}
    void run() {
        std::cout << __PRETTY_FUNCTION__ << ":" << __LINE__ << std::endl;
        std::string line;

        while (getline(is, line)) {
            std::reverse(line.begin(), line.end());
            os << line << std::endl;
        }
    }
};

struct SocketRequest : boost::enable_shared_from_this<SocketRequest> {
    boost::asio::ip::tcp::iostream stream;

    void start() {
        boost::async(boost::launch::async, boost::bind(&SocketRequest::do_run, shared_from_this()));
    }

  private:
    void do_run() {
        return Handler(stream, stream).run();
    }
};

int main() {
    boost::asio::io_service io_service;

    unsigned short port_ = 6767;
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_);
    boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint);

    for (;;)
    {
        boost::shared_ptr<SocketRequest> req = boost::make_shared<SocketRequest>();

        acceptor.accept(*req->stream.rdbuf());
        req->start();
    }
}

对于样本客户:

(for req in HELLO BYE; do sleep 1; netcat 127.0.0.1 6767 <<< "$req"; done)&

打印

void Handler::run():16
OLLEH
void Handler::run():16
EYB

关于c++ - Boost.Asio、tcp::iostream 和多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47437563/

相关文章:

c++ - Windows:获取窗口标题栏的高度

c++ - 如何将文件读入元组 vector ?

c# - MenuStrip 和 ToolStrip 上的 "Red Cross"问题

c++ - Boost.Asio 仅作为 header

[]的C++含义

c++ - Int vs Double 汇编

c++ - 虚函数

java - Perl 共享变量的原子性和可见性

Java Swing 线程库

将 asio 套接字多播 boost 到特定的以太网接口(interface)