boost::asio的类继承体系

简介: boost::asio的类继承体系

asio概述

周末看了asio的网络库,和其他网络库相比,asio更复杂,更加的OO,而且用模板抽象了网络编程的通用操作。

简单来说,Boost.Asio是一个跨平台的、主要用于网络和其他一些底层输入/输出编程的C++库。

Boost.Asio在2003被开发出来,然后于2005年的12月引入到Boost 1.35版本中。原作者是Christopher M. Kohlhoff.

关键词: 跨平台, 稳定, 其次是性能.

简单的例子

展示一个连接并发送字符串的例子, 最要的是如何编译和运行.

server

下面这段代码是从Boost.asio网站上抄过来的

http://think-async.com/Asio/boost_asio_1_10_6/doc/html/boost_asio/examples/cpp03_examples.html

//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
{
public:
    session(boost::asio::io_service& io_service)
        : socket_(io_service)
    {
    }
    tcp::socket& socket()
    {
        return socket_;
    }
    void start()
    {
        socket_.async_read_some(boost::asio::buffer(data_, max_length),
                                boost::bind(&session::handle_read, this,
                                            boost::asio::placeholders::error,
                                            boost::asio::placeholders::bytes_transferred));
    }
    void handle_read(const boost::system::error_code& error,
                     size_t bytes_transferred)
    {
        if (!error)
        {
            boost::asio::async_write(socket_,
                                     boost::asio::buffer(data_, bytes_transferred),
                                     boost::bind(&session::handle_write, this,
                                                 boost::asio::placeholders::error));
        }
        else
        {
            delete this;
        }
    }
    void handle_write(const boost::system::error_code& error)
    {
        if (!error)
        {
            socket_.async_read_some(boost::asio::buffer(data_, max_length),
                                    boost::bind(&session::handle_read, this,
                                                boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred));
        }
        else
        {
            delete this;
        }
    }
private:
    tcp::socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};
class server
{
public:
    server(boost::asio::io_service& io_service, short port)
        : io_service_(io_service),
          acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
    {
        session* new_session = new session(io_service_);
        acceptor_.async_accept(new_session->socket(),
                               boost::bind(&server::handle_accept, this, new_session,
                                           boost::asio::placeholders::error));
    }
    void handle_accept(session* new_session,
                       const boost::system::error_code& error)
    {
        if (!error)
        {
            new_session->start();
            new_session = new session(io_service_);
            acceptor_.async_accept(new_session->socket(),
                                   boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error));
        }
        else
        {
            std::cout <<"handle_acceptor error" << std::endl;
            delete new_session;
        }
    }
private:
    boost::asio::io_service& io_service_;
    tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: async_tcp_echo_server <port>\n";
            return 1;
        }
        boost::asio::io_service io_service;
        using namespace std; // For atoi.
        server s(io_service, atoi(argv[1]));
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}

client

#include <string.h>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/array.hpp>
typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
typedef boost::array<char, 128> buffer_t;
typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
void on_read(boost::system::error_code ec,
             std::size_t len,
             socket_ptr_t socket_ptr,
             buffer_ptr_t buffer_ptr)
{
    if (ec)
        std::cout << "async write error:" << ec.message() << std::endl;
    else
    {
        std::cout << "on_read(), " << std::string((char*)buffer_ptr->begin(), len) << std::endl;
    }
}
void on_write(boost::system::error_code ec,
              std::size_t len,
              socket_ptr_t socket_ptr,
              buffer_ptr_t buffer_ptr)
{
    if (ec)
        std::cout << "async write error:" << ec.message() << std::endl;
    else
    {
        std::cout << "on_write(), write completely: " << len << std::endl;
        socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size()),
                                    boost::bind(&on_read, boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred,
                                                socket_ptr,
                                                buffer_ptr));
    }
}
void on_connect(boost::system::error_code ec, socket_ptr_t socket_ptr)
{
    if (ec)
        std::cout << "asio client: async connect error:" << ec.message() << std::endl;
    else
    {
        std::cout << "on_connect(), " << socket_ptr->remote_endpoint()  << std::endl;
        buffer_ptr_t buffer_ptr(new buffer_t);
        strncpy((char*)buffer_ptr->begin(), "abcdefg", buffer_t::size());
        socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin())),
                                     boost::bind(&on_write,
                                                 boost::asio::placeholders::error,
                                                 boost::asio::placeholders::bytes_transferred,
                                                 socket_ptr,
                                                 buffer_ptr));
    }
}
int main()
{
    boost::asio::io_service ios;
    boost::asio::ip::tcp::endpoint addr(boost::asio::ip::address::from_string("127.0.0.1"), 12345);
    socket_ptr_t conn_socket_ptr(new boost::asio::ip::tcp::socket(ios));
    conn_socket_ptr->async_connect(addr, boost::bind(&on_connect, boost::asio::placeholders::error, conn_socket_ptr));
    ios.run();
    std::cout << "press enter key...";
    std::cin.get();
    return 0;
}

编译运行

c++ echo_server.cpp -I~/Code/boost_1_55_0 -L~/Code/boost_1_55_0/stage/lib/ -lboost_system-mt -lboost_thread-mt -o echo_server -g -O0
   c++ asio_client.cpp -I~/Code/boost_1_55_0 -L~/Code/boost_1_55_0/stage/lib/ -lboost_system-mt -lboost_thread-mt -o asio_client -g -O0

运行

server:
max@max-gentoo ~/Study/Boost $ ./echo_server 12345
client:
max@max-gentoo ~/Study/Boost $ ./asio_client                                                   
on_connect(), 127.0.0.1:12345                                                                  
on_write(), write completely: 7                                                                
on_read(), abcdefg                                                                             
press enter key...

类继承体系分析

asio不仅支持多平台, 还支持多协议tcp和udp, 还支持多线程和同步异步和定时器, 如何抽象的呢?
asio抽象了两个继承体系: 存储套接字的实体(图中的上半部分)和操作相应套接字的service(图中的下半部分).

44b434aff5325be038e66207ed81af8fddc1f9f0.png

在客户端需要连接服务器的12345端口.
首先指定套接字和service:
boost::asio::io_service ios;
    socket_ptr_t conn_socket_ptr(new boost::asio::ip::tcp::socket(ios));
boost::asio::ip::tcp::socket的类型为:
//tcp.hpp
    typedef basic_stream_socket<tcp> socket;
而, basic_stream_socket正是组合procotol和service两种服务的模板类.第二个模板参数的默认值是stream_socket_service:
template <typename Protocol,
    typename StreamSocketService = stream_socket_service<Protocol> >
    class basic_stream_socket : public basic_socket<Protocol, StreamSocketService>
basic_stream_socket继承自basic_socket, basic_socket是个很重要的类, 所有和套接字相关的累都继承自这个类, 比如: basic_seq_socket, basic_raw_socket.
template <typename Protocol, typename SocketService>
class basic_socket
  : public basic_io_object<SocketService>,
    public socket_base
basic_socket同时继承自socket_base和basic_io_object: socket_base封装了socket的基本操作,basic_io_object封装了io的具体操作.

时序

935d22c3a837f518bcc5898965a3b1f97de33249.png

从client端发起异步连接开始.

conn_socket_ptr->async_connect(addr, boost::bind(&on_connect, boost::asio::placeholders::error, conn_socket_ptr));

async_connect需要两个参数:第一个是地址信息;第二个是连接成功后的回调函数。

async_connect方法是在conn_socket父类basic_socket中定义的。显而易见basic_socket需要提供各种socket的操作如: open, bind,connect等套接字的方法.

basic_socket真正发起async_connect操作是通过相应的service完成的: get_servie()返回这种套接字对应的service.

这个service是在何时绑定的呢?还要从类的继承体系中寻找。

template <typename Protocol,
    typename StreamSocketService = stream_socket_service<Protocol> >
    class basic_stream_socket : public basic_socket<Protocol, StreamSocketService>

可见,get_service返回的是stream_socket_service。这个service和protocol是配套的。

stream_socket_service中的async_connect是通过代理类service_impl实现的。

stream_socket_service是个通用的类,适用于各个平台,具体平台的操作是通过具体的service_impl来完成。

#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
  typedef detail::winrt_ssocket_service<Protocol> service_impl_type;
#elif defined(BOOST_ASIO_HAS_IOCP)
  typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
#else
  typedef detail::reactive_socket_service<Protocol> service_impl_type;
#endif

可见,不同平台的处理类通过宏和typedef重新定义为了_impe_type类型。

Linux 平台的_impe_type是reactive_socket_service。

reactive_socket_service发起start_connect_op操作,最终调用基类reactive_socket_service_base的start_connet_op,伪代码如下:

start_connet_op()
{
    socket_ops::connect(impl.socket_, addr, addrlen, op->ec_);
   reactor_.start_op(reactor::connect_op, impl.socket_,
            impl.reactor_data_, op, is_continuation, false)
}

先非阻塞的调用connect方法,然后start_op,像reactor中插入一个回调(闭包)。

这种 nonblocking + callback的模式很经典,上层的任何操作都是nonblocking的,为了防止底层的reactor陷入阻塞而耽误其他的操作,同时上层可以立即返回作其他的事情,而底层通过回调来返回结果。

请记住 nonblcking + callback。

至于start_op的代码,留在下一次讨论。

相关文章
|
安全 算法 编译器
【C++ 泛型编程 进阶篇】深入探究C++模板参数推导:从基础到高级
【C++ 泛型编程 进阶篇】深入探究C++模板参数推导:从基础到高级
1591 3
|
数据处理 Python
Pandas数据处理 | apply() 函数用法指南!
本文介绍一下关于 Pandas 中 apply() 函数的几个常见用法,apply() 函数的自由度较高,可以直接对 Series 或者 DataFrame 中元素进行逐元素遍历操作,方便且高效,具有类似于 Numpy 的特性。
|
人工智能 数据安全/隐私保护 Python
小红书图文生成器,小红书AI图文生成工具,python版本软件
Pillow库自动生成符合平台尺寸要求的配图7;3)利用Playwright实现自动化发布流程6。
|
人工智能 自然语言处理 算法
《解锁跨模态魔法:DALL - E等模型的进阶之路》
DALL·E是OpenAI推出的一款革命性文生图模型,它通过跨模态内容生成技术,将文本描述转化为栩栩如生的图像。作为跨模态变革的领军者,DALL·E从初代到DALL·E3不断进化,新增构图扩展、局部修改和生成变体等功能,并借助ChatGPT优化提示语理解力。它不仅与CLIP等模型协作推动技术生态繁荣,还在广告设计、影视制作、教育和游戏开发等领域展现巨大潜力。尽管面临版权、虚假信息等挑战,DALL·E仍将持续创新,引领创意新时代。
726 9
|
10月前
|
机器学习/深度学习 人工智能 数据可视化
一文看懂决策引擎平台必备功能都有哪些
Together规则引擎是一款决策智能平台,旨在帮助企业高效管理、执行和部署半自动及全自动决策。它融合业务规则、数据分析、机器学习与流程自动化技术,支持多场景智能决策,助力企业提升运营效率与商业价值。
|
传感器 机器学习/深度学习 人工智能
智能照明系统:技术、应用与未来趋势###
【10月更文挑战第15天】 智能照明,正以前所未有的速度革新着我们的世界。它不仅仅是灯泡亮度的简单调节,更是一种融合了先进科技与人性化设计的未来之光。本文将深入浅出地剖析智能照明系统的核心技术,探讨其在不同领域的广泛应用,并展望这一领域的未来发展蓝图。 ###
1121 2
|
开发框架 人工智能 安全
ModelScope魔搭25年5月发布月报
不知不觉间,日历已经翻过了立夏,而开源模型的世界中似乎并没有春夏秋冬。在刚刚过去的四月份,见证了开源社区又一次蓬勃发展的浪潮。以Qwen3家族为代表,一系列新模型的开源为整个生态注入了新的活力。通过全面覆盖多种规格的 dense 与 MoE 模型架构,Qwen3 首次在开源模型中引入“快思考与慢思考” 双模式的支持,获得了广大开发者的热烈欢迎,成为新一代开源大模型的标杆之作。
538 10
|
缓存 运维 Docker
容器化运维:Docker Desktop 占用磁盘空间过大?教你轻松解决!
Windows Docker Desktop 使用过程中,因镜像、容器数据及构建缓存的累积,可能导致磁盘空间占用过高。通过删除无用镜像与容器、压缩磁盘以及清理构建缓存等方法,可有效释放空间。具体步骤包括关闭WSL、使用`diskpart`工具压缩虚拟磁盘、执行`docker buildx prune -f`清理缓存等。这些操作能显著减少磁盘占用,提升系统性能。
6049 5
|
存储 容器
Hashmap1.7和1.8区别
Hashmap1.7和1.8区别
555 0
Hashmap1.7和1.8区别
|
安全 算法 编译器
【C++ 泛型编程 进阶篇】C++ 元模板推导函数调用的结果类型 std::result_of/std::invoke_result全面教程
【C++ 泛型编程 进阶篇】C++ 元模板推导函数调用的结果类型 std::result_of/std::invoke_result全面教程
1432 0

热门文章

最新文章