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 相关的内容:
#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/