Boost ASIO:Network programming

Abstract

Even though Boost.Asio can process any kind of data asynchronously, it is mainly used for network programming. This is because Boost.Asio supported network functions long before additional I/O objects were added. Network functions are a perfect use for asynchronous operations because the transmission of data over a network may take a long time, which means acknowledgments and errors may not be available as fast as the functions that send or receive data can execute.

尽管Asio可以异步处理任何类型的数据,但是主要用于网络编程。这是因为Boost早在添加额外的I/O对象之前,Asio就已经支持网络功能了。网络函数是异步操作的完美应用,因为通过网络传输数据可能需要很长时间,这意味着确认和错误可能没有发送或接收数据的函数执行得快。

Demo

#include <boost/asio/io_service.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <array>
#include <string>
#include <iostream>

using namespace boost::asio;
using namespace boost::asio::ip;

io_service ioservice;
tcp::resolver resolv{ioservice};
tcp::socket tcp_socket{ioservice};
std::array<char, 4096> bytes;

void read_handler(const boost::system::error_code &ec,
  std::size_t bytes_transferred)
{
  if (!ec)
  {
    std::cout.write(bytes.data(), bytes_transferred);
    tcp_socket.async_read_some(buffer(bytes), read_handler);
  }
}

void connect_handler(const boost::system::error_code &ec)
{
  if (!ec)
  {
    std::string r =
      "GET / HTTP/1.1\r\nHost: theboostcpplibraries.com\r\n\r\n";
    write(tcp_socket, buffer(r));
    tcp_socket.async_read_some(buffer(bytes), read_handler);
  }
}

void resolve_handler(const boost::system::error_code &ec,
  tcp::resolver::iterator it)
{
  if (!ec)
    tcp_socket.async_connect(*it, connect_handler);
}

int main()
{
  tcp::resolver::query q{"theboostcpplibraries.com", "80"};
  resolv.async_resolve(q, resolve_handler);
  ioservice.run();
}


在main()中,boost::asio::ip::tcp::resolver::query实例化创建一个q对象。q表示对名称解析器的查询,这是一个boost::asio::ip::tcp::resolver类型的I/O对象。通过将q传递给async_resolve(),将启动一个异步操作来解析名称。解析名称theboostcpplibraries.com。异步操作启动后,在I/O服务对象上调用run(),将控制权传递给操作系统。

当名称被解析后,将调用resolve_handler()。处理程序首先检查名称解析是否成功。这里ec等于0。只有这样,才能访问套接字来建立连接。要连接的服务器地址由第二个参数提供,类型为boost::asio::ip::tcp::resolver::iterator。该参数是名称解析的结果。

对async_connect()的调用之后是对处理程序connect_handler()的调用。同样,首先检查ec以确定是否可以建立连接。如果是,则在套接字上调用async_read_some()。通过这个调用,开始读取数据。接收到的数据存储在数组字节中,它作为第一个参数传递给async_read_some()。

当接收到一个或多个字节并复制到字节中时,调用Read_handler()。类型为std::size_t的bytes_transferred参数包含已经接收到的字节数。通常,处理程序应该首先检查异步操作是否成功完成。只有在这种情况下,才会将数据写入标准输出。

请注意,read_handler()在数据写入std::cout之后再次调用async_read_some()。这是必需的,因为您不能确定在单个异步操作中下载了整个主页并将其复制到字节中。重复调用async_read_some(),然后重复调用read_handler(),只有当连接关闭时才结束,这发生在web服务器已经发送了整个主页。然后read_handler()报告ec中的错误。此时,没有进一步的数据写入std::cout,并且不会在套接字上调用async_read()。因为没有挂起的异步操作,所以程序退出。

#include <boost/asio/io_service.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <string>
#include <ctime>

using namespace boost::asio;
using namespace boost::asio::ip;

io_service ioservice;
tcp::endpoint tcp_endpoint{tcp::v4(), 2014};
tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint};
tcp::socket tcp_socket{ioservice};
std::string data;

void write_handler(const boost::system::error_code &ec,
  std::size_t bytes_transferred)
{
  if (!ec)
    tcp_socket.shutdown(tcp::socket::shutdown_send);
}

void accept_handler(const boost::system::error_code &ec)
{
  if (!ec)
  {
    std::time_t now = std::time(nullptr);
    data = std::ctime(&now);
    async_write(tcp_socket, buffer(data), write_handler);
  }
}

int main()
{
  tcp_acceptor.listen();
  tcp_acceptor.async_accept(tcp_socket, accept_handler);
  ioservice.run();
}

这是一个时间服务器。您可以与telnet客户端连接以获得当前时间。之后,时间服务器关闭。

tcp::v4() 可以替换为address_type::from_string("127.0.0.1")。

时间服务器使用I/O对象boost::asio::ip::tcp::acceptor来接收来自另一个程序的连接。您必须初始化对象,以便它知道在哪个端口上使用哪个协议。在这个例子中,类型为boost::asio::ip::tcp::endpoint的变量tcp_endpoint被用来告诉tcp_acceptor在端口2014上接受互联网协议版本4的传入连接。

在接受者初始化之后,调用listen()来使接受者开始监听。然后调用async_accept()来接受第一次连接尝试。套接字必须作为第一个参数传递给async_accept(),它将用于在新连接上发送和接收数据。

一旦另一个程序建立连接,就调用accept_handler()。如果连接建立成功,当前时间将通过boost::asio::async_write()发送。这个函数将data中的所有数据写入套接字。Boost::asio::ip::tcp::socket还提供了成员函数async_write_some()。当至少发送了一个字节时,这个函数调用处理程序。然后,处理程序必须检查已经发送了多少字节,还有多少字节需要发送。然后,它必须再次调用async_write_some()。可以通过boost::asio::async_write()来避免重复计算剩余的发送字节数和调用async_write_some()。由这个函数开始的异步操作只有在数据中的所有字节都已发送后才会完成。

发送数据之后,调用write_handler()。这个函数调用shutdown(),参数是boost::asio::ip::tcp::socket::shutdown_send,表示程序通过socket发送数据已经完成。由于没有等待的异步操作,示例32.6退出。请注意,尽管data仅用于accept_handler()中,但它不能是局部变量。数据通过boost::asio::buffer()传递给boost::asio::async_write()。当boost::asio::async_write()和accept_handler()返回时,异步操作已经启动,但还没有完成。在异步操作完成之前,数据必须存在。如果data是一个全局变量,这是可以保证的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ym影子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值