boost.asio异步并发Tcp服务器

简介

boost的asio采用的是Proactor模型,该模型的核心思想就是异步IO,IO在事件循环中,每个异步IO都绑定对应的回调函数,当IO完成后,对应的回调函数会在事件循环中执行。

异步并发模型说明

一个TcpServer监听指定的端口,当有客户端请求到来时,会建立一个与之对应的会话,会话的生命周期与用户连接的生命周期一致。

每个异步IO,我们都绑定了一个与之对应的回调函数,这样异步完成之后,会立刻执行对应的回调函数。注意std::enable_from_this的使用方式,为了在回调中使用对应的数据,同时也为了可以智能地管理生命周期,我们直接在异步函数中获取对象本身的智能指针,该类及其对应的方法可以帮助我们实现目的,具体参考代码。

io_context可以理解为一个事件循环,当事件循环上有事件时,执行io_context::run()的线程就会获取对应的事件回调函数,并执行。如果要一个事件循环有多个线程并发执行回调,需要并发执行run函数即可,具体参考main.cpp的方式。io_context::run()如果没有对应的任务,则会自动退出,我们使用work_guard的模式,使之始终运行。

该框架是一个最基础的异步IO的Proactor模型,更复杂的业务逻辑,也只需要在对应的模型下,添加有关的组件即可。

注意,下面的代码不是一个安全的并发模型,这里只是讲了一个代码示例而已,简化复杂度;异步回调写给客户端数据的时候,会有写竞争的情况出现。

代码示例

基于boost 1.70和C++14
CMakeLists.txt

# cmake_minimum_required(VERSION <specify CMake version here>)
project(boost_asio)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS -pthread)
add_executable(boost_asio main.cpp TcpServer.hpp Session.hpp)

Session.hpp

//
// Created by Erick on 2020/2/19.
//

#ifndef BOOST_ASIO_SESSION_HPP
#define BOOST_ASIO_SESSION_HPP


#include <boost/asio/ip/tcp.hpp>
#include <iostream>

class Session : public std::enable_shared_from_this<Session> {
	using SessionSocketPtr = std::shared_ptr<boost::asio::ip::tcp::socket>;
public:
    explicit Session(SessionSocketPtr sk) : m_socket(std::move(sk)) {}

    void start() {
        boost::asio::async_read_until(*m_socket, m_streamBuf, "\r\n",
                                      [self = shared_from_this()](const boost::system::error_code &ec,
                                                                  std::size_t bytes_transferred) {
                                          if (ec.failed()) {
                                              std::cout << "session error: " << ec.message() << ", thread_id: "
                                                        << std::this_thread::get_id() << std::endl;
                                              return;
                                          }
                                          std::cout << "Thread: " << std::this_thread::get_id() << ", Get User data: "
                                                    << std::istream(&self->m_streamBuf).rdbuf()
                                                    << std::endl;
                                          self->start();  // 异步继续读
                                      });
    }

private:
    SessionSocketPtr m_socket;
    boost::asio::streambuf m_streamBuf;
};

#endif //BOOST_ASIO_SESSION_HPP

TcpServer.hpp

//
// Created by Erick on 2020/2/19.
//

#ifndef BOOST_ASIO_TCPSERVER_HPP
#define BOOST_ASIO_TCPSERVER_HPP

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include "Session.hpp"

// 异步的TCP服务器
class TcpServer : public std::enable_shared_from_this<TcpServer> {
public:
    explicit TcpServer(boost::asio::io_context &ioc, int port) :
            io_context(ioc),
            m_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) {
        std::cout << "start TcpServer...\n";
    }

    TcpServer(TcpServer &) = delete;

    TcpServer(TcpServer &&) = delete;

    void start() {
        auto socket = std::make_shared<boost::asio::ip::tcp::socket>(io_context);
        m_acceptor.async_accept(*socket,
                                [socket, self = shared_from_this()](boost::system::error_code ec) {
                                    if (ec.failed()) {
                                        std::cout << "async_accept error: " << ec.message() << std::endl;
                                    }
                                    auto session = std::make_shared<Session>(socket);
                                    session->start();  // 这里启动一个会话
                                    std::cout << "thread_id: " << std::this_thread::get_id() << ", create a session\n";
                                    self->start();     // 继续重新启动
                                });
    }

private:
    boost::asio::io_context &io_context;
    boost::asio::ip::tcp::acceptor m_acceptor;
};


#endif //BOOST_ASIO_TCPSERVER_HPP

main.cpp

#include <iostream>
#include <thread>
#include "TcpServer.hpp"

const auto N = std::thread::hardware_concurrency();
using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;

int main() {
    std::cout << "begin asio model" << std::endl;
    boost::asio::io_context io_context;
    work_guard_type work_guard(io_context.get_executor());  // 启动work_guard,即使没有任务也不停止io_context
    std::vector<std::thread> threads;
    for (auto i = 0; i < N; ++i) {
        threads.emplace_back(std::thread([&]() {
            io_context.run();
        }));
    }

    int port;
    std::cout << "input port: ";
    std::cin >> port;
    auto tcpServer = std::make_shared<TcpServer>(io_context, port);
    tcpServer->start();  // 异步启动服务器,不阻塞
    for (auto &t: threads) {
        if (t.joinable()) {
            t.join();
        }
    }
    std::cout << "end asio model" << std::endl;
    return 0;
}

参考资料:

  • https://dens.website/tutorials/cpp-asio/multithreading-2
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值