Boost.Asio库HTTPServer例子解读(二)——单个io_context和一个调用io_context :: run()的线程池
文章目录
模型优势
单个连接处理,多个后台处理,发挥多线程优势
主要的类
重要实现
- server中的run()方法,构造线程队列病启动所有线程
- 构造线程时要使用server自己的io_context
官方代码代码地址
https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/examples/cpp03_examples.html
简化后的代码如下
客户端
#include <string>
#include <iostream>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
enum {
max_length = 1024
};
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::socket s(io_context);
tcp::resolver resolver(io_context);
boost::asio::connect(s, resolver.resolve(argv[1], argv[2]));
std::string request(argv[3]);
boost::asio::write(s, boost::asio::buffer(request, request.size()));
char reply[max_length];
size_t reply_length = boost::asio::read(s,
boost::asio::buffer(reply, request.size()));
std::cout << "Reply is: ";
std::cout.write(reply, reply_length);
std::cout << "\n";
// s.close();
}
catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
服务器端
//server.hpp
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
#include "session.hpp"
using boost::asio::ip::tcp;
using boost::asio::io_context;
using session_sptr = std::shared_ptr<session>;
class server {
public:
server(const std::string &address, const std::string &port, size_t thread_pool_size)
: thread_pool_size_(thread_pool_size), acceptor_(ioc_) {
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
boost::asio::ip::tcp::resolver resolver(acceptor_.get_executor());
boost::asio::ip::tcp::endpoint endpoint =
*resolver.resolve(address, port).begin();
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
do_accept();
}
~server() {}
public:
void run();
private:
void do_accept();
private:
std::size_t thread_pool_size_;
io_context ioc_;
tcp::acceptor acceptor_;
session_sptr new_session_;
};
//server.cpp
#include <vector>
#include <thread>
#include <boost/bind.hpp>
#include "server.hpp"
void server::run() {
// Create a pool of threads to run all of the io_contexts.
std::vector<std::shared_ptr<std::thread>> threads;
for (std::size_t i = 0; i < thread_pool_size_; ++i) {
std::shared_ptr<std::thread> thread(new std::thread(
boost::bind(&boost::asio::io_context::run, &ioc_)));
threads.push_back(thread);
}
// Wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
threads[i]->join();
}
void server::do_accept() {
new_session_.reset(new session(ioc_));
acceptor_.async_accept(new_session_->socket(), [this](boost::system::error_code ec) {
if (!ec) {
//请不要在start()里面进行耗时的计算,不然会阻塞在start()函数里
//也不可以用start()调用耗时的函数进行计算,不然会阻塞在start()函数里
new_session_->start();
do_accept();
} else {
std::cout << "ERROR: " << ec.message() << std::endl;
return;
}
});
}
session
session负责read和write
//session.hpp
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
/*
* server负责连接
* session负责产生socket和读写
*/
using boost::asio::ip::tcp;
using boost::asio::io_context;
class session : public std::enable_shared_from_this<session>, private boost::noncopyable {
public:
session(boost::asio::io_context &ioc) : socket_(ioc) {}
~session() {
std::cout << "~session() " << std::this_thread::get_id() << std::endl;
}
void start() {
do_read();
}
boost::asio::ip::tcp::socket &socket() {
return socket_;
}
private:
void do_read();
void do_write(std::size_t length);
tcp::socket socket_;
enum {
max_length = 1024
};
char buffer_[max_length];
// std::vector<char> buffer_;
};
//session.cpp
#include <thread>
#include <chrono>
#include "session.hpp"
void session::do_read() {
std::cout << "do_read() " << std::endl;
auto self(shared_from_this());
//耗时的计算可以放在这里作为异步调用
socket_.async_read_some(boost::asio::buffer(buffer_, max_length),
[self](boost::system::error_code ec, std::size_t length) {
if (!ec) {
//用std::this_thread::sleep_for来模拟耗时计算
std::this_thread::sleep_for(std::chrono::seconds(5));
self->do_write(length);
} else {
std::cout << "ERROR: " << ec.message() << std::endl;
return;
}
});
}
void session::do_write(std::size_t length) {
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(buffer_),
[self](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
// self->do_read();
boost::system::error_code ignored_ec;
self->socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignored_ec);
} else {
std::cout << "ERROR: " << ec.message() << std::endl;
return;
}
});
}