TCP,UDP和ICMP
Asio提供对TCP,UDP和ICMP的集成支持。
TCP客户端
主机地址被实现为一个resolver,主机和服务地址被查找并转化为多个endpoint端点:
ip::tcp::resolver resolver(my_io_service);
ip::tcp::resolver::query query("www.boodt.org", "http");
ip::tcp::resolver::iterator iter = resolver.resolve(query);
ip::tcp::resolver::iterator end; // End Marker.
while(iter != end)
{
ip::tcp::endpoint endpoint = *iter++;
std::cout << endpoint << std::endl;
}
端点列表可能会同时包含IPv4和IPv6的端点,程序会依次尝试直到一个端点成功运转。这保证了客户端程序不用依赖特定的IP版本。
为了简化开发,TCP客户端会通过使用connect()或者async_connect()实现连接的建立,它们会尝试列表中的每一个端点直到socket成功连接。例如在一个单连接中:
asio::async_connect(socket_, iter,
boost::bing(&client::handler_connect, this,
asio::placeholders::error));
// ...
void handle_connect(const error_code& error)
{
if(!error)
{
// Start read or write operations.
}
else
{
// Handle error.
}
}
当有特定的端点是可用的,socket就被建立和连接了:
ip::tcp::socket socket(my_io_service);
socket。connect(endpoint);
数据操作会通过recieve(),async_recieve(),send()和async_send()等成员函读写到正连接着的TCP socket。但是,它们有可能是短读写,这时候使用read(),async_read(),write()和async_write()。
TCP服务器
使用acceptor来完成TCP连接。
ip::tcp::acceptor acceptor(my_io_service, my_endpoint);
...
ip::tcp::socket socket(my_io_service);
acceptor.accept(socket);
当socket被正确的接受连接后,它的数据操作和客户端相同。
UDP
UDP的主机地址接收也通过resolver来实现:
ip::udp::resolver resolver(my_io_service);
ip::udp::resolver::query query("localhost", "daytime");
ip::udp::resolver::iterator iter = resolver.resolve(query);
...
UDP的socket一般绑定在本地的端点上,如下的代码会创建一个IPv4版本的UDP socket,它会绑定到“任何”地址的12345端口:
ip::udp::endpoint endpoint(ip::udp::v4(), 12345);
ip::udp::socket socket(my_io_service, endpoint);
对于没有连接到的UDP socket,使用成员函数receive_from(),async_receive_from(),send_to()和async_send_to()来进行数据IO,而对于已经连接的UDP socket,使用receive(),async_receive(),send()和async_send()等成员函数(译者注:此处应该是和WinSock API中相似,调用一次connect,返回-1表示当前地址不可访问,能访问则保存,所以是连接验证而并非是连接,UDP是无连接的)。
ICMP
ICMP也是使用resolver来实现主机地址解析:
ip::icmp::resolver resolver(my_io_service);
ip::icmp::resolver::query query("localhost", "");
ip::icmp::resolver iterator iter = resolver.resolve(query);
...
ICMP socket绑定到本地端点,下面的代码展示了一个连接到“任意”地址的IPv6版的ICMP socket。
ip::icmp::endpoint endpoint(ip::icmp::v6(), 0);
ip::icmp::socket socket(my_io_service, endpoint);
端口号对于ICMP没有任何意义,也不会被使用。
数据操作使用receive_from(),async_receive_from(),send_to()和async_send_to()等函数。
参见
ip::tcp, ip::udp, ip::icmp, daytime protocol tutorials, ICMP ping example