Boost 是一个开源的 C++ 库集合,提供了许多实用的功能,如网络编程、图形界面、数学计算等。Boost 库可以与标准 C++ 库无缝集成,扩展了 C++ 的功能。

# 安装 Boost 库

通过 APT 包管理器安装 Boost 库:

# 1. 更新软件包索引
sudo apt update
# 2. 安装 Boost 核心库和开发文件(包含头文件和静态 / 动态库)
sudo apt install libboost-all-dev -y
# 3. 验证安装(检查版本)
boostversion=$(cat /usr/include/boost/version.hpp | grep "#define BOOST_VERSION" | awk '{print $3}')
echo "Boost 版本: $boostversion"

# 基本使用

同步操作会阻塞当前线程,直到操作完成。异步操作则不会阻塞线程,通过回调函数在操作完成后触发。

# 同步

#include <iostream>
#include<boost/asio.hpp>
int main(){
    boost::asio::io_context io;
    boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5));
    // 同步,阻塞线程 5 秒
    t.wait();
    //wait () 返回,定时器资源(如系统句柄)被自动释放
    std::cout<<"Hello,world!"<<std::endl;
    return 0;
}

定时器
steady_timerBoost.Asio 提供的定时器类,用于在指定时间后执行回调函数。

steady_timer 的构造函数需要 io_context 参数,目的是 ​显式声明 该定时器依赖 ** 的事件循环。这种设计确保类型安全,避免隐式关联导致的错误。

io_context 的作用
io_contextBoost.Asio 的核心组件,负责调度以及执行所有异步(如 DNS 解析、连接、读写)和同步操作的生命周期。(如定时器、网络 I/O)。

# 异步

异步操作需要事件循环来驱动, io_context::run() 方法启动事件处理流程。

#include <iostream>
#include<boost/asio.hpp>
void print(const boost::system::error_code& a /*e*/)
{
    std::cout<<a<<std::endl;
    std::cout<<"Hello,world!"<<std::endl;
}
int main(){
    boost::asio::io_context io;
    boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5)); 
    t.async_wait(&print);   // 异步,不会阻塞线程,回调函数 print 会在 5 秒后执行
    io.run();
    return 0;
}

io.run() 是异步编程的核心,负责监听操作系统异步操作(如定时器到期、网络请求完成)的完成事件,确保资源(如 定时器socket )被正确释放,并触发回调函数。

特性 同步代码 异步代码
​执行方式 阻塞等待( wait() 非阻塞,通过回调触发
​事件循环 无需 io.run() 必须调用 io.run()
​线程占用 单线程阻塞 单线程 / 多线程(由 run() 决定)
​适用场景 简单、短耗时操作 高并发、实时性要求高的场景

​时间点计算

  1. 函数式编程
#include <functional>
#include <iostream>
#include <boost/asio.hpp>
void print(const boost::system::error_code& /*e*/,
    boost::asio::steady_timer* t, int* count)
{
  if (*count < 5)
  {
    std::cout << *count << std::endl;
    ++(*count);
    // 新到期时间 = 当前到期时间 + 1 秒
    t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));
    // 异步等待新到期时间
    t->async_wait(std::bind(print,
        std::placeholders::_1, t, count));
  }
}
int main()
{
  boost::asio::io_context io;
  int count = 0;
  boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1));
  
  t.async_wait(std::bind(print,
    std::placeholders::_1, &t, &count));
  io.run();
  std::cout << "Final count is " << count << std::endl;
  return 0;
}
// 输出
// 0
// 1
// 2
// 3
// 4
// Final count is 5
// 新到期时间 = 当前到期时间 + 1 秒
t->expires_at(t->expires_at() + boost::asio::chrono::seconds(1));

t->expires_at() 返回定时器当前的到期时间点( system_clock::time_point 类型), boost::asio::chrono::seconds(1) 表示一个 ​时间间隔​( duration 类型)。两者相加会生成新的到期时间点:

这种设计允许动态调整定时器的触发时间,适用于需要重复执行任务的场景(如每隔 1 秒打印一次计数器)。

​类型匹配的底层原理

expires_at() 的参数类型是 system_clock::time_point ,而 boost::asio::chrono::seconds(1) 的类型是 duration , 明确指定了时间单位(秒),避免了因隐式类型转换导致的单位混淆(如误用毫秒或微秒)。
Boost.Asiochrono 库通过 ​类型推导运算符重载,自动将 duration 转换为 time_point ,确保表达式合法。
若直接使用 t->expires_at(1) ,编译器会报错,因为 1 的类型是 int ,无法隐式转换为 time_point

  1. 面向对象编程
#include <functional> 
#include <iostream>
#include <boost/asio.hpp>
class printer
{
public:
    // 构造函数,初始化 timer_成员和 count_成员
    printer(boost::asio::io_context& io)
    : timer_(io, boost::asio::chrono::seconds(1)),  // 初始化 timer_成员
      count_(0)                                     // 初始化 count_成员
    {
    //bind () 函数将成员函数 print 绑定到当前对象上,并作为回调函数传递给 timer_.async_wait ()
        timer_.async_wait(std::bind(&printer::print, this)); 
    }
    // 析构函数
    ~printer()
    {
        std::cout<< "final count is "<< count_ <<std::endl;
    }
    void print(){
        if(count_<5)
        {
            std::cout << count_ <<std::endl;
            ++count_;
            // 新到期时间 = 当前到期时间 + 1 秒
            timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1));
            timer_.async_wait(std::bind(&printer::print,this));
        }
    }
private:
    boost::asio::steady_timer timer_;
    int count_;
};
int main()
{
  boost::asio::io_context io;
  printer p(io);
  io.run();
  return 0;
}
// 输出
// 0
// 1
// 2
// 3
// 4
// final count is 5

优缺点对比

维度 ​函数式 ​面向对象
​代码简洁性 ✅ 代码简短,适合简单场景 ❌ 类定义增加代码量
​安全性 ❌ 需手动管理指针,易出错 ✅ 自动管理资源,避免悬垂指针
​扩展性 ❌ 修改需调整参数传递链 ✅ 新增功能只需扩展类方法
​异步上下文 ❌ 依赖外部变量,多线程下可能竞争 ✅ 成员变量天然隔离,适合多线程异步任务
​性能开销 ✅ 无虚函数或类结构开销 ❌ 类实例化带来微小内存开销

线程安全的异步任务队列(通过 Strand 串行化)

#include <functional>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
// 通过 strand_ 序列化回调函数的执行
class printer
{
public:
    printer(boost::asio::io_context& io)
        : strand_(boost::asio::make_strand(io)),     // 初始化 strand_成员
        timer1_(io, boost::asio::chrono::seconds(1)),// 初始化 timer1_成员
        timer2_(io, boost::asio::chrono::seconds(1)),// 初始化 timer2_成员
        count_(0)
    {
        // 使用 strand_串行化异步操作,bind_executor () 将异步操作绑定到 strand_上
        timer1_.async_wait(boost::asio::bind_executor(strand_,
            std::bind(&printer::print1, this)));
  
        timer2_.async_wait(boost::asio::bind_executor(strand_,
            std::bind(&printer::print2, this)));
    }
    ~printer()
    {
      std::cout << "Final count is " << count_ << std::endl;
    }
    void print1()
    {
        if (count_ < 10)
        {
        std::cout << "Timer 1: " << count_ << std::endl;
        ++count_;
        timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1));
        timer1_.async_wait(boost::asio::bind_executor(strand_,
                std::bind(&printer::print1, this)));
        }
    }
    void print2()
    {
        if (count_ < 10)
        {
        std::cout << "Timer 2: " << count_ << std::endl;
        ++count_;
        timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1));
        timer2_.async_wait(boost::asio::bind_executor(strand_,
                std::bind(&printer::print2, this)));
        }
    }
private:
  boost::asio::strand<boost::asio::io_context::executor_type> strand_;
  boost::asio::steady_timer timer1_;
  boost::asio::steady_timer timer2_;
  int count_;
};
int main()
{
  boost::asio::io_context io;
  printer p(io);
  // 创建一个新线程,执行 Lambda 表达式中的代码 (即 io.run ())
  std::thread t([&]{ io.run(); });
  io.run();
  // 阻塞主线程,直到 t 线程结束
  t.join();
  return 0;
}

代码通过多线程运行 io_context 的事件循环,结合 strand_ 的序列化机制,实现了高效的事件响应与线程安全的逻辑处理。虽然有两个线程处理事件,但任务逻辑( print1 / print2 )本质上是单线程化的,因此更准确地说,这是多线程协作处理事件循环,但任务执行是序列化的。

Lambda 的捕获方式 [&]

  • [&] 表示以引用方式捕获所有外部变量。
    Lambda 内部可以直接访问外部作用域的所有变量(如 io ),且操作的是原变量本身,而非副本。
  • ​对比其他捕获方式:
    [=]:以值方式捕获(创建副本,可能影响性能)。
    [io]:仅捕获 io 变量(需显式指定)。
    此处 [&] 简化了代码,但需确保 Lambda 生命周期内外部变量有效。
  1. 代码的多线程机制
    ​线程数量与任务类型
    代码中通过 std::thread t([&]{ io.run(); }) 创建了一个工作线程,主线程也调用 io.run() ,因此 ​总共有两个线程运行 io_context 的事件循环。这两个线程会并行处理 io_context 中的异步操作(如定时器到期事件)。

​异步操作的并行性
timer1_timer2_ 是独立的定时器,它们的异步等待操作会被提交到 io_context 的任务队列中。理论上,这两个定时器的到期事件可能被分配到不同的线程处理。但由于绑定了 strand_ ,所有回调会被强制序列化执行,​实际表现为单线程顺序处理​。

  1. Strand 的核心作用
    ​线程安全与顺序保证
    strand_ Boost.Asio 提供的一种隐式同步机制,其作用包括:

​序列化回调执行:所有通过 strand_ 提交的回调(如 print1print2 )会按提交顺序依次执行,即使多个线程在运行 io_context
​消除数据竞争:对共享资源 count_ 的修改(如 ++count_ )会被限制在同一个线程上下文中,无需显式加锁。
​代码中的具体实现

timer1_.async_wait(boost::asio::bind_executor(strand_, ...));

将定时器的回调函数绑定到 strand_ 的执行器上,确保回调在 strand_ 的调度下运行。因此,即使两个定时器的到期事件被不同线程触发, print1print2 也不会并发执行。

  1. 执行流程示例
    假设两个定时器同时到期:
    1. ​事件触发: timer1_timer2_ 的到期事件被提交到 io_context
    2. ​线程分配:事件可能被主线程或工作线程 t 处理。
    3. ​Strand 调度:无论哪个线程处理事件,回调函数会被 strand_ 序列化。例如:
      • 线程 1 执行 print1 → 输出 Timer 1: 0
      • 线程 2 执行 print2 → 但需等待 print1 完成后才能执行,输出 Timer 2: 1
      • 最终 count_ 会严格递增至 10,无并发问题

# TCP

TCP 连接

  • TCP 连接是面向连接的,可靠的,基于字节流的传输层通信协议。
  • TCP 连接需要三次握手来建立连接,四次挥手来关闭连接。
  • TCP 连接的建立和关闭都需要消耗一定的资源,因此需要合理管理 TCP 连接。
  • TCP 连接的建立和关闭都需要消耗一定的资源,因此需要合理管理 TCP 连接。

UDP 连接

  • UDP 连接是无连接的,不可靠的,基于数据报的传输层通信协议。
  • UDP 连接不需要建立连接,只需要发送数据报即可。
  • UDP 连接不需要关闭连接,只需要发送数据报即可。
  • UDP 连接的建立和关闭不需要消耗资源,因此不需要管理 UDP 连接。

TCP 和 UDP 的区别

TCP UDP
面向连接 无连接
可靠 不可靠
基于字节流 基于数据报
需要三次握手 不需要握手
需要四次挥手 不需要挥手
建立和关闭连接需要消耗资源 建立和关闭连接不需要消耗资源
需要管理连接 不需要管理连接

TCP 和 UDP 的应用场景

  • TCP 连接适用于需要可靠传输的场景,如文件传输、邮件发送等。
  • UDP 连接适用于需要快速传输的场景,如视频直播、实时游戏等。

TCP 和 UDP 的编程模型

  • TCP 连接的编程模型通常包括客户端和服务端两部分,客户端通过 socket 函数创建一个套接字,然后通过 connect 函数连接到服务端,然后通过 sendrecv 函数进行数据的发送和接收,最后通过 close 函数关闭连接。

# 同步 TCP 时间服务器

  1. 命令行参数
int main(int argc, char* argv[]){}

argc(Argument Count)​
表示命令行参数的总数量(包括程序名本身)。

  • 例如,若用户输入 ./myprogram arg1 arg2 ,则 argc 的值为 ​3​(程序名 + 2 个参数)。

argv[](Argument Vector)​
是一个字符串指针数组,存储所有命令行参数的具体值。

  • argv[0] :程序自身的名称(如 “./myprogram”)。
  • argv[1] ~ argv[argc-1] :用户输入的其他参数。
  • argv[argc] :固定为 NULL(表示数组结束)。

示例代码:

#include <stdio.h>
int main(int argc, char* argv[]) {
    printf("参数总数 argc = %d\n", argc);
    
    for (int i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    
    return 0;
}

运行示例:

./myprogram arg1 arg2 arg3

输出:

参数总数 argc = 4
argv[0] = ./myprogram
argv[1] = arg1
argv[2] = arg2
argv[3] = arg3
  1. 同步 TCP 服务端

服务端:监听端口 13 , 发送时间数据

#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string() {
    std::time_t now = std::time(nullptr);
    return std::ctime(&now); // 格式示例: "Wed Oct  2 00:00:00 2023\n"
}
int main() {
    try {
        boost::asio::io_context io_context;
        // 监听端口 13 (需管理员权限) 或改用其他端口如 12345
        tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 13));
        std::cout << "Daytime 服务器启动,监听端口: " << acceptor.local_endpoint().port() << std::endl;
        for (;;) {
            tcp::socket socket(io_context);
            acceptor.accept(socket); // 阻塞等待客户端连接
            std::cout << "客户端连接: " << socket.remote_endpoint() << std::endl;
            std::string message = make_daytime_string();
            boost::system::error_code ignored_error;
            
            // 发送时间数据后立即关闭连接
            boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
        }
    } catch (std::exception& e) {
        std::cerr << "异常: " << e.what() << std::endl;
    }
    return 0;
}
  1. 同步 TCP 客户端

客户端:连接服务器,发送数据,接收响应,关闭连接。

整体流程

  • **​初始化 I/O 上下文:** 创建 io_context 对象,管理所有 I/O 操作。
  • **​解析目标地址:** 将用户输入的主机名和服务名转换为具体的网络地址列表。
  • **​创建套接字:** 准备用于通信的套接字对象。
  • **​连接服务器:** 按地址列表尝试连接,直到成功或全部失败。
#include <array>
#include <iostream>
#include <boost/asio.hpp>
//using 导入某个变量到当前作用域 
using boost::asio::ip::tcp; //tcp 命名空间
int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      //std::cerr 通常用于输出错误信息,这些信息不会被重定向到文件或管道,而是直接显示在终端上。
      std::cerr << "Usage: client <host>" << std::endl;
      return 1;
    }
    
    boost::asio::io_context io_context;
    // 创建解析器对象,用于将 ​主机名 和 ​服务名 / 端口号 转换为具体的网络地址(IP + 端口)。
    tcp::resolver resolver(io_context);      //io_context:绑定到同一个 I/O 上下文,确保解析操作由该上下文管理。
    tcp::resolver::results_type endpoints =     
      resolver.resolve(argv[1], "cc");       // 解析用户输入的主机名和服务名,生成可能的网络端点列表。
    tcp::socket socket(io_context);          // 套接字绑定到同一个 I/O 上下文,确保其操作由该上下文管理。
    boost::asio::connect(socket, endpoints); // 尝试连接到服务器。
    for (;;)
    {
      std::array<char, 128> buf;
      boost::system::error_code error;
      //read_some 函数用于从 TCP 连接中读取数据。buffer 函数用于创建一个缓冲区,用于存储读取的数据。size_t 类型表示读取的字节数。
      size_t len = socket.read_some(boost::asio::buffer(buf), error); 
      if (error == boost::asio::error::eof) //eof 表示连接已关闭。
        break; // Connection closed cleanly by peer.
      else if (error)
        throw boost::system::system_error(error); // Some other error.
      std::cout.write(buf.data(), len);//buf.data () 返回缓冲区的指针,len 表示读取的字节数。
    }
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}
  1. boost::asio::io_context io_context;

​作用: 创建 I/O 上下文对象,管理所有底层 I/O 操作(如网络通信、定时器等)。
​原理:

  • io_contextBoost.Asio 的 ​事件循环核心,负责调度和处理异步操作。
    所有异步操作(如连接、读写)都需要通过它执行。
  1. tcp::resolver resolver(io_context);

​作用: 创建解析器对象,用于将 ​主机名 和 ​服务名 / 端口号 转换为具体的网络地址(IP + 端口)。
​参数:

  • io_context :绑定到同一个 I/O 上下文,确保解析操作由该上下文管理。
    ​功能:
  • 解析器 ( resolver ) 支持 DNS 查询,将域名(如 "example.com" )解析为 IP 地址。
  • 将服务名(如 "http" )解析为端口号(如 80 )。
  1. tcp::resolver::results_type endpoints = resolver.resolve(argv[1], "cc");

​作用: 解析用户输入的主机名和服务名,生成可能的网络端点列表。
​参数:

  • argv[1] :命令行输入的主机名(如 "localhost""192.168.1.100" )。
  • "cc" :服务名或端口号。这里可能是自定义的服务名(需系统配置)或直接表示端口号(如 "12345" )。
    ​返回值:
  • endpoints 是一个端点列表,包含所有可能的 IP 地址和端口组合(例如 IPv4IPv6 地址)。
  1. tcp::socket socket(io_context);

​作用: 创建 TCP 套接字对象,用于与服务器通信。
​参数:

  • io_context :套接字绑定到同一个 I/O 上下文,确保其操作由该上下文管理。
    ​功能:
  • 套接字是网络通信的端点,通过它可以发送和接收数据。
  1. boost::asio::connect(socket, endpoints);

​作用: 尝试连接到服务器。
​参数:

  • socket :上一步创建的套接字。
  • endpoints :解析得到的端点列表。
    ​行为:
  • 按顺序尝试连接 endpoints 中的每一个端点(如 IPv4 地址优先,失败后尝试 IPv6 )。
  • 当某个端点连接成功时,停止尝试。
  • 如果所有端点均连接失败,抛出异常。

# 异步 TCP 时间服务器

  1. 主函数入口
int main()
{
  try
  {
    boost::asio::io_context io_context;      // 创建 IO 上下文,管理所有异步操作
    tcp_server server(io_context);          // 创建 TCP 服务器实例,初始化监听
    io_context.run();                       // 启动事件循环,处理异步操作
  }
  catch (std::exception& e)                 // 异常处理
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}
  • io_contextBoost.Asio 的核心,负责调度异步任务。
  • tcp_server 初始化时会开始监听连接。
  • io_context.run() 会阻塞主线程,持续处理异步事件,直到所有任务完成。
  1. ​TCP 服务器初始化(tcp_server 构造函数)​
tcp_server(boost::asio::io_context& io_context)
  : io_context_(io_context),
    acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) // 绑定 IPv4 地址的 13 端口
{
  start_accept(); // 开始异步等待客户端连接
}
  • acceptor_ 初始化时绑定到本地 13 端口。
  • start_accept() 启动异步接受连接的过程。
  1. 异步接受连接(start_accept)​
void start_accept()
{
  tcp_connection::pointer new_connection = tcp_connection::create(io_context_); // 创建新连接对象
  acceptor_.async_accept(                       // 异步接受连接
      new_connection->socket(),
      [this, new_connection](const boost::system::error_code& error) {
          handle_accept(error, new_connection); // 连接完成时调用处理函数
      });
}
  • tcp_connection::create 创建新的连接对象,其 socketio_context 管理。
  • async_accept 异步等待客户端连接。当有连接到来时, lambda 被调用,传递错误码和连接对象。
  1. 处理新连接(handle_accept)​
void handle_accept(const boost::system::error_code& error, tcp_connection::pointer new_connection)
{
  if (!error)
  {
    new_connection->start(); // 启动数据发送流程
  }
  start_accept(); // 继续监听下一个连接
}
  • 如果没有错误,调用 new_connection->start() 开始处理客户端请求。
  • 无论是否出错,再次调用 start_accept() ,形成循环监听。
  1. TCP 连接处理(tcp_connection::start)
void start()
{
  message_ = make_daytime_string(); // 生成当前时间字符串
  auto self(shared_from_this());    // 获取 shared_ptr,延长对象生命周期
  boost::asio::async_write(         // 异步发送数据
      socket_,
      boost::asio::buffer(message_),
      [this, self](const auto& error, size_t bytes) {
          handle_write(error, bytes); // 发送完成后的回调
      });
}
  • make_daytime_string() 生成当前时间的字符串。
  • shared_from_this() 确保在异步操作期间对象不会被销毁。
  • async_write 异步发送数据,完成后调用 handle_write
  1. 数据发送完成处理(handle_write)​
void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/)
{
  // 此处可添加发送完成后的逻辑,例如关闭连接
}
  • 当前代码未处理发送结果,但可在此处添加错误处理或资源释放逻辑。
  1. 生成时间字符串(make_daytime_string)​
std::string make_daytime_string()
{
  time_t now = time(0);
  return ctime(&now); // 示例输出:"Wed May 22 15:42:36 2024\n"
}
  • 返回的字符串末尾包含换行符,符合 Daytime 协议标准。

异步执行流程总结:​

  • 服务器启动,监听端口 13。
  • 当客户端连接时,async_accept 完成,触发 handle_accept。
  • 无错误则调用 start () 发送时间数据。
  • 数据发送完成后,由 handle_write 处理后续逻辑(当前为空)。
  • 服务器循环调用 start_accept,持续监听新连接。

** 关键点:**​

  • ​生命周期管理: 通过 shared_from_this()shared_ptr 确保异步操作期间对象存活。
  • ​异步链式调用: async_accept handle_acceptasync_writehandle_write 形成异步链。
  • ​端口重用: Daytime 协议使用 13 端口,需确保权限允许(Linux/Mac 可能需要 sudo 运行)。

完整代码:

#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
  time_t now = time(0);
  return ctime(&now); // 示例输出:"Wed May 22 15:42:36 2024\n"
}
class tcp_connection
  : public std::enable_shared_from_this<tcp_connection>
{
public:
  typedef std::shared_ptr<tcp_connection> pointer;
  static pointer create(boost::asio::io_context& io_context)
  {
    return pointer(new tcp_connection(io_context));
  }
  tcp::socket& socket()
  {
    return socket_;
  }
  void start()
  {
    message_ = make_daytime_string(); // 生成当前时间字符串
    auto self(shared_from_this());    // 获取 shared_ptr,延长对象生命周期
    boost::asio::async_write(         // 异步发送数据
        socket_,
        boost::asio::buffer(message_),
        [this, self](const auto& error, size_t bytes) {
            handle_write(error, bytes); // 发送完成后的回调
        });
  }
private:
  tcp_connection(boost::asio::io_context& io_context)
    : socket_(io_context)
  {
  }
  void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/)
  {
    // 此处可添加发送完成后的逻辑,例如关闭连接
  }
  tcp::socket socket_;
  std::string message_;
};
class tcp_server
{
public:
  tcp_server(boost::asio::io_context& io_context)
    :io_context_(io_context),
    acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) // 绑定 IPv4 地址的 13 端口
  {
    start_accept(); // 开始异步等待客户端连接
  }
private:
  void start_accept() {
    tcp_connection::pointer new_connection = tcp_connection::create(io_context_);// 创建新连接对象
    acceptor_.async_accept(         // 异步接受连接
        new_connection->socket(),
        [this, new_connection](const boost::system::error_code& error) {
            // 这里的 this 指向当前 tcp_server 对象
            handle_accept(error, new_connection);
        }
    );
  } 
  void handle_accept(const boost::system::error_code& error, tcp_connection::pointer new_connection)
  {
    if (!error)
    {
      new_connection->start(); // 启动数据发送流程
    }
    start_accept(); // 继续监听下一个连接
  }
  boost::asio::io_context& io_context_;
  tcp::acceptor acceptor_;
};
int main()
{
  try
  {
    boost::asio::io_context io_context;      // 创建 IO 上下文,管理所有异步操作
    tcp_server server(io_context);          // 创建 TCP 服务器实例,初始化监听
    io_context.run();                       // 启动事件循环,处理异步操作
  }
  catch (std::exception& e)                 // 异常处理
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

# UPD

# 同步 UDP 客户端

#include <array>
#include <iostream>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: client <host>" << std::endl;
      return 1;
    }
    boost::asio::io_context io_context;
    udp::resolver resolver(io_context);
    udp::endpoint receiver_endpoint =
      *resolver.resolve(udp::v4(), argv[1], "daytime").begin();
    udp::socket socket(io_context);
    socket.open(udp::v4());
    std::array<char, 1> send_buf  = <!--swig0-->;
    socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
    std::array<char, 128> recv_buf;
    udp::endpoint sender_endpoint;
    size_t len = socket.receive_from(
        boost::asio::buffer(recv_buf), sender_endpoint);
    std::cout.write(recv_buf.data(), len);
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

# 异步 UDP 服务端

#include <array>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
std::string make_daytime_string()
{
  using namespace std; // For time_t, time and ctime;
  time_t now = time(0);
  return ctime(&now);
}
class udp_server
{
public:
  udp_server(boost::asio::io_context& io_context)
    : socket_(io_context, udp::endpoint(udp::v4(), 13))
  {
    start_receive();
  }
private:
  void start_receive()
  {
    socket_.async_receive_from(
        boost::asio::buffer(recv_buffer_), remote_endpoint_,
        std::bind(&udp_server::handle_receive, this,
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }
  void handle_receive(const boost::system::error_code& error,
      std::size_t /*bytes_transferred*/)
  {
    if (!error)
    {
      std::shared_ptr<std::string> message(
          new std::string(make_daytime_string()));
      socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
          std::bind(&udp_server::handle_send, this, message,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
      start_receive();
    }
  }
  void handle_send(std::shared_ptr<std::string> /*message*/,
      const boost::system::error_code& /*error*/,
      std::size_t /*bytes_transferred*/)
  {
  }
  udp::socket socket_;
  udp::endpoint remote_endpoint_;
  std::array<char, 1> recv_buffer_;
};
int main()
{
  try
  {
    boost::asio::io_context io_context;
    udp_server server(io_context);
    io_context.run();
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}

# 组合 TCP/UDP

#include <array>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using boost::asio::ip::udp;
std::string make_daytime_string()
{
  using namespace std; // For time_t, time and ctime;
  time_t now = time(0);
  return ctime(&now);
}
class tcp_connection
  : public std::enable_shared_from_this<tcp_connection>
{
public:
  typedef std::shared_ptr<tcp_connection> pointer;
  static pointer create(boost::asio::io_context& io_context)
  {
    return pointer(new tcp_connection(io_context));
  }
  tcp::socket& socket()
  {
    return socket_;
  }
  void start()
  {
    message_ = make_daytime_string();
    boost::asio::async_write(socket_, boost::asio::buffer(message_),
        std::bind(&tcp_connection::handle_write, shared_from_this()));
  }
private:
  tcp_connection(boost::asio::io_context& io_context)
    : socket_(io_context)
  {
  }
  void handle_write()
  {
  }
  tcp::socket socket_;
  std::string message_;
};
class tcp_server
{
public:
  tcp_server(boost::asio::io_context& io_context)
    : io_context_(io_context),
      acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
  {
    start_accept();
  }
private:
  void start_accept()
  {
    tcp_connection::pointer new_connection =
      tcp_connection::create(io_context_);
    acceptor_.async_accept(new_connection->socket(),
        std::bind(&tcp_server::handle_accept, this, new_connection,
          boost::asio::placeholders::error));
  }
  void handle_accept(tcp_connection::pointer new_connection,
      const boost::system::error_code& error)
  {
    if (!error)
    {
      new_connection->start();
    }
    start_accept();
  }
  boost::asio::io_context& io_context_;
  tcp::acceptor acceptor_;
};
class udp_server
{
public:
  udp_server(boost::asio::io_context& io_context)
    : socket_(io_context, udp::endpoint(udp::v4(), 13))
  {
    start_receive();
  }
private:
  void start_receive()
  {
    socket_.async_receive_from(
        boost::asio::buffer(recv_buffer_), remote_endpoint_,
        std::bind(&udp_server::handle_receive, this,
          boost::asio::placeholders::error));
  }
  void handle_receive(const boost::system::error_code& error)
  {
    if (!error)
    {
      std::shared_ptr<std::string> message(
          new std::string(make_daytime_string()));
      socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
          std::bind(&udp_server::handle_send, this, message));
      start_receive();
    }
  }
  void handle_send(std::shared_ptr<std::string> /*message*/)
  {
  }
  udp::socket socket_;
  udp::endpoint remote_endpoint_;
  std::array<char, 1> recv_buffer_;
};
int main()
{
  try
  {
    boost::asio::io_context io_context;
    tcp_server server1(io_context);
    udp_server server2(io_context);
    io_context.run();
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }
  return 0;
}