=================================版权声明=================================
版权声明:原创文章 谢绝转载 啥说的,鄙视那些无视版权随意抓取博文的爬虫小网站,祝你们早升极乐。
请通过右侧公告中的“联系邮箱(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)的比较
=======================================================================
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
他们的映射关系
=======================================================================
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的基本支持。
=======================================================================