11-Daytime.6-An asynchronous UDP daytime server

#include <asio.hpp>

#include <spdlog/spdlog.h>

using asio::ip::udp;

std::string make_daytimme_string()
{
    using namespace std;
    time_t now = time(nullptr);
    return ctime(&now);
}

class udp_server {
public:
    // 构造函数初始化一个套接字以监听UDP端口13。
    udp_server(asio::io_context& io_context)
        : socket_(io_context, udp::endpoint(udp::v4(), 13))
    {
        start_receive();
    }

private:
    void start_receive()
    {
        // 函数ip::udp::socket::async_receive_from()将使应用程序在后台监听新的请求。
        // 当接收到这样的请求时,io_context对象将调用handle_receive()函数,并传入两个参数:
        // 一个std::error_code类型的值(指示操作成功或失败)
        // 一个size_t类型的值bytes_transferred(指定接收到的字节数)。
        socket_.async_receive_from(asio::buffer(recv_buffer_), remote_endpoint_,
            std::bind(&udp_server::handle_receive, this, asio::placeholders::error,
                asio::placeholders::bytes_transferred));
    }

    // 响应客户端请求
    void handle_receive(const std::error_code& error, std::size_t byte_tansferred)
    {
        // 错误参数包含异步操作的结果。
        // 由于我们只提供了1字节的recv_buffer_来容纳客户端请求,如果客户端发送的数据超过此大小,
        // io_context对象将返回错误。若出现此类错误,我们可以忽略。
        if (!error) {
            // 创建发送内容对象
            std::shared_ptr<std::string> message(new std::string(make_daytimme_string()));

            // 调用async_send_to方法将响应发送回客户端。
            socket_.async_send_to(asio::buffer(*message), remote_endpoint_,
                std::bind(&udp_server::handle_send, this,
                    message, asio::placeholders::error,
                    asio::placeholders::bytes_transferred));

            //在启动异步操作时,如果使用std::bind,必须仅指定与处理程序参数列表匹配的参数。
            // 在本程序中,两个参数占位符(asio::placeholders::error和asio::placeholders::bytes_transferred)都可能已被移除。
            //开始监听下一个客户端请求。
            start_receive();
            // 对于此客户请求的进一步操作现在由handle_send()负责。
        }
    }

    // handle_send()函数在服务请求完成后被调用。
    void handle_send(std::shared_ptr<std::string> message,
        const std::error_code& error, std::size_t byte_tansferred) { }

private:
    udp::socket socket_;
    udp::endpoint remote_endpoint_;
    std::array<char, 1> recv_buffer_;
};

int main()
{
    try {
        // 创建一个服务器对象以接收传入的客户端请求,并运行io_context对象。
        asio::io_context io_context;
        udp_server server(io_context);
        io_context.run();
    } catch (const std::exception& e) {
        spdlog::error("Exception: {}", e.what());
        return 1;
    }
}