#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;
}
}