Daytime.1——一个同步的 TCP daytime 客户端 #
本教程演示如何使用 asio 实现 TCP 客户端应用程序。 首先包含必要的头文件:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
这个应用程序的目的是访问 daytime 服务,因此需要用户指定服务器。
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: client <host>" << std::endl;
return 1;
}
所有使用 asio 的程序都至少需要一个 I/O 执行上下文(execution context),例如 io_context 对象。
boost::asio::io_context io_context;
使用 ip::tcp::resolver 对象将指定为应用程序参数的服务器名称转换为 TCP 连接点(endpoint)。
tcp::resolver resolver(io_context);
解析器(resolver )获取主机名和服务名称,并将它们转换为连接点列表。 使用argv[1]
中指定的服务器名称和服务名称(在本例中为“daytime”)执行解析调用。
返回的连接点列表是 ip::tcp::resolver::results_type 类型的对象。 该对象是一个范围(range),具有可用于迭代结果的 begin() 和 end() 成员函数。
tcp::resolver::results_type endpoints =
resolver.resolve(argv[1], "daytime");
现在我们创建并连接套接字。 上面获得的列表可能同时包含 IPv4 和 IPv6 连接点,因此我们需要测试每个连接点,直到找到一个有效的连接点。 这使得客户端程序不依赖于特定的IP版本。 boost::asio::connect() 函数会自动为我们完成此操作。
tcp::socket socket(io_context);
boost::asio::connect(socket, endpoints);
连接成功后,我们需要做的是读取 daytime 服务的响应。
我们使用boost::array
来存储接收到的数据。boost::asio::buffer()
函数会自动确定数组的大小,以防止缓冲区溢出。我们也可以使用char []
来代替 boost::array
。
for (;;)
{
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
当服务器关闭连接时,ip::tcp::socket::read_some() 函数会以boost::asio::error::eof
错误退出,使得我们可以知道何时退出循环。
if (error == boost::asio::error::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);
}
最后,处理任何可能抛出的异常。
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}