[关闭]
@john-lee 2021-01-03T07:52:28.000000Z 字数 2463 阅读 648

TCP、UDP 和 ICMP

Boost.Asio


Boost.Asio 对互联网协议 TCP、UDP 和 ICMP 提供现成的支持。

TCP 客户端

主机名解析使用解析程序执行,在解析程序中查找主机名和服务名并将其转换为一个或多个端点(endpoint):

  1. ip::tcp::resolver resolver(my_io_context);
  2. ip::tcp::resolver::query query("www.boost.org", "http");
  3. ip::tcp::resolver::iterator iter = resolver.resolve(query);
  4. ip::tcp::resolver::iterator end; // End marker.
  5. while (iter != end)
  6. {
  7. ip::tcp::endpoint endpoint = *iter++;
  8. std::cout << endpoint << std::endl;
  9. }

上面获得的端点列表可能同时包含 IPv4 和 IPv6 端点,因此程序应该尝试其中的每一个端点,直到找到一个有效的端点为止。这使得客户端程序独立于特定的 IP 版本。

为了简化与协议无关的程序的开发,TCP 客户端可以使用自由函数connect()async_connect()建立连接。这些操作将尝试列表中的每个端点,直到成功连接套接字。例如,单个调用:

  1. ip::tcp::socket socket(my_io_context);
  2. boost::asio::connect(socket, resolver.resolve(query));

将同步尝试所有端点,直到成功连接一个端点。同样,异步连接可以这样写:

  1. boost::asio::async_connect(socket_, iter,
  2. boost::bind(&client::handle_connect, this,
  3. boost::asio::placeholders::error));
  4. // ...
  5. void handle_connect(const error_code& error)
  6. {
  7. if (!error)
  8. {
  9. // Start read or write operations.
  10. }
  11. else
  12. {
  13. // Handle error.
  14. }
  15. }

当特定端点可用时,可以创建并连接套接字:

  1. ip::tcp::socket socket(my_io_context);
  2. socket.connect(endpoint);

可以使用receive()async_receive()成员函数从连接的 TCP 套接字读取数据或用send()async_send()成员函数向其写入数据。但是,由于这样做可能导致短写或短读,因此应用程序通常会改用以下操作:read()async_read()write()async_write()

TCP 服务端

程序使用接受器接受传入的 TCP 连接:

  1. ip::tcp::acceptor acceptor(my_io_context, my_endpoint);
  2. ...
  3. ip::tcp::socket socket(my_io_context);
  4. acceptor.accept(socket);

成功接受套接字后,可以从中读取或写入,如上面的TCP客户端所示。

UDP

UDP 主机名解析也使用解析器执行:

  1. ip::udp::resolver resolver(my_io_context);
  2. ip::udp::resolver::query query("localhost", "daytime");
  3. ip::udp::resolver::iterator iter = resolver.resolve(query);
  4. ...

UDP 套接字通常绑定到本地端点。以下代码将创建IP 版本 4 的 UDP 套接字并将其绑定到端口 12345 上的“any”地址:

  1. ip::udp::endpoint endpoint(ip::udp::v4(), 12345);
  2. ip::udp::socket socket(my_io_context, endpoint);

使用receive_from()async_receive_from()成员函数从未连接的 UDP 套接字读取数据或用send_to()async_send_to()成员函数向其写入数据。对于已连接的 UDP 套接字,请使用receive()async_receive()send()async_send()成员函数。

ICMP

与 TCP 和 UDP 一样,使用解析器执行 ICMP 主机名解析:

  1. ip::icmp::resolver resolver(my_io_context);
  2. ip::icmp::resolver::query query("localhost", "");
  3. ip::icmp::resolver::iterator iter = resolver.resolve(query);
  4. ...

ICMP 套接字可以绑定到本地端点。以下代码将创建 IP 版本 6 的 ICMP 套接字并将其绑定到“any”地址:

  1. ip::icmp::endpoint endpoint(ip::icmp::v6(), 0);
  2. ip::icmp::socket socket(my_io_context, endpoint);

端口号不用于 ICMP。

可以使用receive_from()async_receive_from()成员函数从未连接的 ICMP 套接字读取数据或用send_to()async_send_to()成员函数向其写入数据。

另请参阅

ip::tcp, ip::udp, ip::icmp,daytime 协议教程,ICMP ping 示例。


Copyright © 2003-2020 Christopher M. Kohlhoff

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注