08-Daytime.3-An asynchronous TCP daytime server
// tcp_server.h
#pragma once
#include <asio.hpp>
#include <memory>
#include <string>
using asio::ip::tcp;
inline 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
// 我们将使用 shared_ptr 和 enable_shared_from_this,
// 因为我们希望在仍有操作引用 tcp_connection 对象时保持其存活状态。
: public std::enable_shared_from_this<tcp_connection> {
public:
typedef std::shared_ptr<tcp_connection> pointer;
static pointer create(asio::io_context& io_context)
{
return pointer(new tcp_connection(io_context));
}
tcp::socket& socket()
{
return socket_;
}
// 在函数start()中,我们调用asio::async_write()向客户端发送数据。
// 请注意,这里使用的是asio::async_write()而非ip::tcp::socket::async_write_some(),以确保整个数据块被完整发送。
void start()
{
// 要发送的数据存储在类成员message_中,因为我们需要保持数据有效,直到异步操作完成。
message_ = make_daytime_string();
// 在启动异步操作时,如果使用std::bind,必须只指定与处理程序参数列表匹配的参数。
// 在本程序中,两个参数占位符(asio::placeholders::error和asio::placeholders::bytes_transferred)都可能被移除,
// 因为它们并未在handle_write()中使用。
asio::async_write(socket_, asio::buffer(message_),
std::bind(&tcp_connection::handle_write, shared_from_this(),
asio::placeholders::error,
asio::placeholders::bytes_transferred));
//此客户端连接的后续操作现在由handle_write()负责处理。
}
private:
tcp_connection(asio::io_context& io_context)
: socket_(io_context)
{
}
void handle_write(const std::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
tcp::socket socket_;
std::string message_;
};
class tcp_server {
public:
tcp_server(asio::io_context& io_context)
: io_context_(io_context)
// 构造函数初始化一个接收器,监听tcp::v4()地址的13端口
, acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
// 该函数创建一个socket,同时初始化一个异步接受操作,等待客户端连接
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,
asio::placeholders::error));
}
// 该函数会在初始化的异步接受操作完成后被调用
// 该函数响应客户端请求,然后调用start_accept()函数,开始下一次接受操作
void handle_accept(tcp_connection::pointer new_connection,
const std::error_code& error)
{
if (!error) {
new_connection->start();
}
start_accept();
}
asio::io_context& io_context_;
tcp::acceptor acceptor_;
};
运行效果与之前的相同,只是一个是同步,一个是异步。