单个io_context和一个调用io_context :: run()的线程池的HTTP服务器

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;
                                 }
                             });
}
发布了80 篇原创文章 · 获赞 68 · 访问量 7544

猜你喜欢

转载自blog.csdn.net/weixin_44048823/article/details/103296687