Daytime.1 同步的 Tcp Daytime 客户端

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