=================================版权声明=================================

版权声明:原创文章 谢绝转载  啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

请通过右侧公告中的“联系邮箱(wlsandwho@foxmail.com)”联系我

勿用于学术性引用。

勿用于商业出版、商业印刷、商业引用以及其他商业用途。                   

 

本文不定期修正完善。

本文链接:http://www.cnblogs.com/wlsandwho/p/5050318.html

耻辱墙:http://www.cnblogs.com/wlsandwho/p/4206472.html

=======================================================================

没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

=======================================================================

BOOST几乎是奇技淫巧的堆砌,来自大神的深深恶意。没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

这个库确实不是给初学者像使用C++标准库那样用的。没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

我觉得在使用前,最好了解下四人帮的那个设计模式。没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

=======================================================================

本文为Boost.Asio下Overview中的内容,我把自己感兴趣的地方进行了摘录、翻译、解释。

=======================================================================

官方文档概述中给的模型,以套接字为例,概要的讲了同步模型和异步模型都做了什么事情,我略作修改。没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

 

=======================================================================

知识储备:Proactor和Reactor没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

两种高性能I/O设计模式(Reactor/Proactor)的比较

Reactor模式,或者叫反应器模式

=======================================================================

Boost.Asio支持异步操作(通过Proactor模式)和同步操作。没啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。

Proactor模式可以不使用多线程来实现并发。

=======================================================================

Boost.Asio和多线程的那些事儿

我觉得,这里用“线程可重入”来表示更好一点。

简单的说,用io_service::run()来执行完成例程,用io_service::post()来向线程池投递任务。

 

我并不想在Linux和Windows之外的平台上用Boost,事实上我只打算在Windows上写代码。忽略这块应该没问题。

=======================================================================

当一个名词不知道怎么翻译时,那就不要翻译。

=======================================================================

Strands

1 只在一个线程里调用io_service::run(),这是隐式的。

2 像HTTP那种在一个连接里只有一个异步操作链的情况,这是隐式的。

3 明确调用io_service::strand的是显示的。

(这都说的些什么啊,不懂。感觉Strands像是把要并行执行的东西放在一个受到访问锁保护的queue里。就像麻绳一样,好多股拧成了一根。)

======================================================================= 

Buffers

boost::asio::basic_streambuf

使用data()来获得输入顺序。(这样在循环里就能获得输入数据。)

使用prepare()来获得输出顺序。(这样在循环里就能获得输出数据。)

使用commit()来把输出数据附加到输入数据的尾部。(从这篇文档不能看出有毛用,但看起来是复制缓存的。)

使用consume()来移除输入数据的开始部分。(看起来可以强制认定某块数据为脏数据,然后丢弃掉。)

 

按字节复制缓冲

1 boost::asio::streambuf sb;
2 
3 std::size_t n = boost::asio::read_until(sock, sb, '\n');//从Socket中获得数据
4 
5 boost::asio::streambuf::const_buffers_type bufs = sb.data();//复制到常量缓冲中
6 
7 std::string line(boost::asio::buffers_begin(bufs),boost::asio::buffers_begin(bufs) + n);//复制到string中

=======================================================================

Streams,Short Reads and Short Writes

基于流式的I/O模型

1 使用SyncReadStream的read_some()来实现同步读。

3 使用SyncWriteStream的write_some()来实现同步写。

2 使用AsyncReadStream的async_read_some()来实现异步读。

4 使用AsyncWriteStream的async_write_some()来实现异步写。

 

传输精确的字节:

read()

async_read()

write()

async_write()

=======================================================================

Reactor-Style Operations

看起来像是说,对于那些自己实现了通信功能的第三方组件想要集成到使用Asio库中时,Asio库提供了null_buffer类型用于读写操作。

在I/O对象就绪前,nullbuffer操作不会返回。

看例子中是read_handler处理程序完成操作后,async_read_some函数才会返回。

=======================================================================

Line-Based Operations

 

按行读取 "\r\n"

read_until

async_read_until

 

读取数据直到遇到空格

typedef boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> iterator;

std::pair<iterator, bool>
match_whitespace(iterator begin, iterator end)
{
  iterator i = begin;
  while (i != end)
    if (std::isspace(*i++))
      return std::make_pair(i, true);

  return std::make_pair(i, false);
}

boost::asio::streambuf b;
boost::asio::read_until(s, b, match_whitespace);

 读取数据直到遇到指定字符

class match_char
{
public:
  explicit match_char(char c) : c_(c) {}

  template <typename Iterator>
  std::pair<Iterator, bool> operator()(Iterator begin, Iterator end) const
  {
    Iterator i = begin;
    while (i != end)
      if (c_ == *i++)
        return std::make_pair(i, true);

    return std::make_pair(i, false);
  }

private:
  char c_;
};

namespace boost { namespace asio {
  template <> struct is_match_condition<match_char>
    : public boost::true_type {};
} } // namespace boost::asio

boost::asio::streambuf b;
boost::asio::read_until(s, b, match_char('a'));

 

(没看懂is_match_condition是想干什么。看起来是向命名空间里添加了扩展。没具体例子没看出有什么用。)

=======================================================================

Custom Memory Allocation

说了一大堆,大概就是一切都考虑好了,只要放心的用这两个函数就行了:

1 void* asio_handler_allocate(size_t, ...);
2 void asio_handler_deallocate(void*, size_t, ...);
3 
4 //分配
5 void* pointer = asio_handler_allocate(size, &h);
6 //回收
7 asio_handler_deallocate(pointer, size, &h);

 

这段不知道什么意思。

=======================================================================

Handler Tracking

使用BOOST_ASIO_ENABLE_HANDLER_TRACKING来帮助异步调试。

=======================================================================

Stackless Corutiones

协同例程类为非栈式协同例程提供支持。非栈式协同例程允许程序以极小的代价用同步的方式实现异步逻辑。

 1 struct session : boost::asio::coroutine
 2 {
 3   boost::shared_ptr<tcp::socket> socket_;
 4   boost::shared_ptr<std::vector<char> > buffer_;
 5 
 6   session(boost::shared_ptr<tcp::socket> socket)
 7     : socket_(socket),
 8       buffer_(new std::vector<char>(1024))
 9   {
10   }
11 
12   void operator()(boost::system::error_code ec = boost::system::error_code(), std::size_t n = 0)
13   {
14     if (!ec) reenter (this)
15     {
16       for (;;)
17       {
18         yield socket_->async_read_some(boost::asio::buffer(*buffer_), *this);
19         yield boost::asio::async_write(*socket_, boost::asio::buffer(*buffer_, n), *this);
20       }
21     }
22   }
23 };

黑科技 看不懂

=======================================================================

Stackful Coroutines

spawn()允许程序用同步的方式实现异步逻辑。

 1 boost::asio::spawn(my_strand, do_echo);
 2 
 3 // ...
 4 
 5 void do_echo(boost::asio::yield_context yield)
 6 {
 7   try
 8   {
 9     char data[128];
10     for (;;)
11     {
12       std::size_t length =
13         my_socket.async_read_some(
14           boost::asio::buffer(data), yield);
15 
16       boost::asio::async_write(my_socket,
17           boost::asio::buffer(data, length), yield);
18     }
19   }
20   catch (std::exception& e)
21   {
22     // ...
23   }
24 }

黑科技 看不懂

=======================================================================

TCP,UDP and ICMP

Boost.Asio为TCP、UDP、ICMP提供了现成的支持。听起来很贴心的样子。

 

使用resolver来进行主机名解析。

通过查找来解析主机名和服务名,然后转换成一个或多个端点。

1 ip::tcp::resolver resolver(my_io_service);
2 ip::tcp::resolver::query query("www.boost.org", "http");//参数2可以直接写端口号“80”。
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 }

 

下面的代码可以对每个端点进行尝试直到能够建立一个连接

(同步的代码)

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

异步的做法:

 1 boost::asio::async_connect(socket_, iter,boost::bind(&client::handle_connect, this,boost::asio::placeholders::error));
 2 
 3 // ...
 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_service);
2 socket.connect(endpoint);

 

在TCP上,recvive()、async_receive()、send()、async_send是短读短写(short writes or reads),所以通常用下面的这些:
read()、async_read()、write()、async_write。

 

TCP Servers

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

 

 

UDP

UDP的主机名解析也使用resolver。

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

 

UDP套接字通常绑定到本地端点。下面的代码将创建一个IP版本4 UDP套接字并将其绑定到任意地址的12345端口

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

 

未连接的UDP,使用receive_from()、async_receive_from()、send_to()、async_send_to()。

已连接的UDP,使用receive()、async_receive()、send()、async_send()。

 

 

ICMP

ICMP的主机名解析也是用resolver。

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

 

一个ICMP可以绑定本地端点。下面的代码将创建一个IP版本6 ICMP套接字并将其绑定到任意地址

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

 

使用receive_from()、async_receive_from()、send_to()、async_send_to()。

=======================================================================

其他协议

可以通过下面的协议来扩展。

generic::datagram_protocol

generic::raw_protocol

generic::seq_packet_protocol

generic::stream_protocol

他们可以指定地址协议簇

1 boost::asio::generic::stream_protocol::socket my_socket(my_io_service);
2 my_socket.open(boost::asio::generic::stream_protocol(AF_INET,IPPROTO_TCP));
3 ...

端点模板类boost::asio::generic::basic_endpoint支持上述的协议。也能够自动作出转换。

1 boost::asio::ip::tcp::endpoint my_endpoint1 = ...;
2 boost::asio::generic::stream_protocol::endpoint my_endpoint2(my_endpoint1);
1 boost::asio::generic::stream_protocol::socket my_socket(my_io_service);
2 boost::asio::ip::tcp::endpoint my_endpoint = ...;
3 my_socket.connect(my_endpoint);

 

Accepting Generic Sockets

如果类型能够转换的话,可以直接使用。

1 boost::asio::ip::tcp::acceptor my_acceptor(my_io_service);
2 ...
3 boost::asio::generic::stream_protocol::socket my_socket(my_io_service);
4 my_acceptor.accept(my_socket);

=======================================================================

Socket Iostreams

Boost.Asio在socket之上实现了输入输出流。

1 ip::tcp::iostream stream("www.boost.org", "http");
2 if (!stream)
3 {
4   // Can't connect.
5 }
io_service ios;

ip::tcp::endpoint endpoint(tcp::v4(), 80);
ip::tcp::acceptor acceptor(ios, endpoint);

for (;;)
{
  ip::tcp::iostream stream;
  acceptor.accept(*stream.rdbuf());
  ...
}

可以用expires_at()和expires_from_now来给超时设定截止时间。

=======================================================================

The BSD Socket API and Boost.Asio

他们的映射关系

BSD Socket API Elements

Equivalents in Boost.Asio

socket descriptor - int (POSIX) or SOCKET (Windows)

For TCP: ip::tcp::socket, ip::tcp::acceptor

For UDP: ip::udp::socket

basic_socket, basic_stream_socket, basic_datagram_socket, basic_raw_socket

in_addr, in6_addr

ip::address, ip::address_v4, ip::address_v6

sockaddr_in, sockaddr_in6

For TCP: ip::tcp::endpoint

For UDP: ip::udp::endpoint

ip::basic_endpoint

accept()

For TCP: ip::tcp::acceptor::accept()

basic_socket_acceptor::accept()

bind()

For TCP: ip::tcp::acceptor::bind(), ip::tcp::socket::bind()

For UDP: ip::udp::socket::bind()

basic_socket::bind()

close()

For TCP: ip::tcp::acceptor::close(), ip::tcp::socket::close()

For UDP: ip::udp::socket::close()

basic_socket::close()

connect()

For TCP: ip::tcp::socket::connect()

For UDP: ip::udp::socket::connect()

basic_socket::connect()

getaddrinfo(), gethostbyaddr(), gethostbyname(), getnameinfo(), getservbyname(), getservbyport()

For TCP: ip::tcp::resolver::resolve(), ip::tcp::resolver::async_resolve()

For UDP: ip::udp::resolver::resolve(), ip::udp::resolver::async_resolve()

ip::basic_resolver::resolve(), ip::basic_resolver::async_resolve()

gethostname()

ip::host_name()

getpeername()

For TCP: ip::tcp::socket::remote_endpoint()

For UDP: ip::udp::socket::remote_endpoint()

basic_socket::remote_endpoint()

getsockname()

For TCP: ip::tcp::acceptor::local_endpoint(), ip::tcp::socket::local_endpoint()

For UDP: ip::udp::socket::local_endpoint()

basic_socket::local_endpoint()

getsockopt()

For TCP: ip::tcp::acceptor::get_option(), ip::tcp::socket::get_option()

For UDP: ip::udp::socket::get_option()

basic_socket::get_option()

inet_addr(), inet_aton(), inet_pton()

ip::address::from_string(), ip::address_v4::from_string(), ip_address_v6::from_string()

inet_ntoa(), inet_ntop()

ip::address::to_string(), ip::address_v4::to_string(), ip_address_v6::to_string()

ioctl()

For TCP: ip::tcp::socket::io_control()

For UDP: ip::udp::socket::io_control()

basic_socket::io_control()

listen()

For TCP: ip::tcp::acceptor::listen()

basic_socket_acceptor::listen()

poll(), select(), pselect()

io_service::run(), io_service::run_one(), io_service::poll(), io_service::poll_one()

Note: in conjunction with asynchronous operations.

readv(), recv(), read()

For TCP: ip::tcp::socket::read_some(), ip::tcp::socket::async_read_some(), ip::tcp::socket::receive(), ip::tcp::socket::async_receive()

For UDP: ip::udp::socket::receive(), ip::udp::socket::async_receive()

basic_stream_socket::read_some(), basic_stream_socket::async_read_some(), basic_stream_socket::receive(), basic_stream_socket::async_receive(), basic_datagram_socket::receive(), basic_datagram_socket::async_receive()

recvfrom()

For UDP: ip::udp::socket::receive_from(), ip::udp::socket::async_receive_from()

basic_datagram_socket::receive_from(), basic_datagram_socket::async_receive_from()

send(), write(), writev()

For TCP: ip::tcp::socket::write_some(), ip::tcp::socket::async_write_some(), ip::tcp::socket::send(), ip::tcp::socket::async_send()

For UDP: ip::udp::socket::send(), ip::udp::socket::async_send()

basic_stream_socket::write_some(), basic_stream_socket::async_write_some(), basic_stream_socket::send(), basic_stream_socket::async_send(), basic_datagram_socket::send(), basic_datagram_socket::async_send()

sendto()

For UDP: ip::udp::socket::send_to(), ip::udp::socket::async_send_to()

basic_datagram_socket::send_to(), basic_datagram_socket::async_send_to()

setsockopt()

For TCP: ip::tcp::acceptor::set_option(), ip::tcp::socket::set_option()

For UDP: ip::udp::socket::set_option()

basic_socket::set_option()

shutdown()

For TCP: ip::tcp::socket::shutdown()

For UDP: ip::udp::socket::shutdown()

basic_socket::shutdown()

sockatmark()

For TCP: ip::tcp::socket::at_mark()

basic_socket::at_mark()

socket()

For TCP: ip::tcp::acceptor::open(), ip::tcp::socket::open()

For UDP: ip::udp::socket::open()

basic_socket::open()

socketpair()

local::connect_pair()

Note: POSIX operating systems only.

=======================================================================

Timers

长时间运行的IO操作通常需要在限定的时间内完成。截止时间可以是绝对时间,但通常使用相对时间。

异步等待操作使用相对时间的例子:

1 io_service i;
2 ...
3 deadline_timer t(i);
4 t.expires_from_now(boost::posix_time::seconds(5));
5 t.wait();

程序在异步等待操作使用相对时间的例子:

1 void handler(boost::system::error_code ec) { ... }
2 ...
3 io_service i;
4 ...
5 deadline_timer t(i);
6 t.expires_from_now(boost::posix_time::milliseconds(400));
7 t.async_wait(handler);
8 ...
9 i.run();

绝对时间、相对时间

1 boost::posix_time::time_duration time_until_expiry
2   = t.expires_from_now();
1 deadline_timer t2(i);
2 t2.expires_at(t.expires_at() + boost::posix_time::seconds(30));

=======================================================================

Serial Ports

Boost.Asio的串口类能够在Windows和Linux上通用。

以stream的形式打开串口。

可以使用read()、async_read()、write()、async_write()、read_until()、async_read_until()。

需要配置9600、N、8、1之类的东西。

=======================================================================

Signal Handling

Boost.Asio通过signal_set来支持信号处理。能用于Windows平台。

 1 void handler(const boost::system::error_code& error,int signal_number)
 2 {
 3   if (!error)
 4   {
 5     // A signal occurred.
 6   }
 7 }
 8 
 9 ...
10 
11 // Construct a signal set registered for process termination.
12 boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
13 
14 // Start an asynchronous wait for one of the signals to occur.
15 signals.async_wait(handler);

=======================================================================

UNIX Domain Sockets(POSIX)

Stream-Oriented File Descriptors(POSIX)

Fork(POSIX)

=======================================================================

Stream-Oriented HANDLEs

Boost.Asio在Windows上用HANDLE实现了异步读写。这些HANDLE必须支持IO完成端口。

(命名管道支持,匿名管道不支持。)

下面是管道的例子:

1 HANDLE handle = ::CreateFile(...);
2 windows::stream_handle pipe(my_io_service, handle);

然后可以使用read()、async_read()、write()、async_write()、read_until()、async_read_until()。

=======================================================================

Random-Access HANDLEs

1 HANDLE handle = ::CreateFile(...);
2 windows::random_access_handle file(my_io_service, handle);

短读短写read_some_at()async_read_some_at()write_some_at()async_write_some_at()。

持续读写read_at()async_read_at()write_at()async_write_at()。

=======================================================================

Object HANDLEs

Boost.Asio提供了Windows特定的异步等待操作类,包括从句柄到内核对象的类型。

  • Change notification                更改通知
  • Console input                        控制台输入
  • Event                                   事件
  • Memory resource notification   内存资源通知
  • Process                                 处理器?
  • Semaphore                            信号量
  • Thread                                  线程
  • Waitable timer                       可等待计时器

例如在事件上执行异步操作

1 HANDLE handle = ::CreateEvent(...);
2 windows::object_handle file(my_io_service, handle);

然后可以使用wait()或asyc_wait()来等待,直到内核对象变为有信号状态。

=======================================================================

SSL

Boost.Asio提供了SSL的基本支持。

=======================================================================