爱热闹的小马驹 · 两个人在一起,比喜欢更重要的是信任|约会|亲 ...· 4 周前 · |
骑白马的包子 · Gene Regulation and ...· 11 月前 · |
含蓄的番茄 · 搬运工盒子? - 知乎· 1 年前 · |
有胆有识的雪糕 · 看嘉庆通宝最新价格,过1000元的不止文庆版 ...· 1 年前 · |
爱笑的汉堡包 · 东台创新� - 搜狗图片搜索· 1 年前 · |
Christopher Kohlhoff
以Boost1.0的软件授权进行发布(见附带的LICENSE_1_0.txt文件或从 http://www.boost.org/LICENSE_1_0.txt )
Boost.Asio是用于网络和低层IO编程的跨平台C++库,为开发者提供了C++环境下稳定的异步模型.
应用程序与外界交互的方式有很多,可通过文件,网络,串口或控制台.例如在网络通信中,完成独立的IO操作需要很长时间.对应用程序开发者提出了一个挑战.
Boost.Asio 提供了管理需长时间运行操作的工具,但不必涉及到线程的并发模式和显示锁定.
Boost.Asio 库使用C++来实现,提供如网络编程等常用的操作系统接口. Boost.Asio实现了如下目标:
· 可移植性Portability. 库支持一系列的常用系统操作,具有稳定的跨平台特性.
· 可扩展性Scalability. 库可以帮助开发者构建数千并发连接的网络应用程序.库中实现的每个系统操作都使用了最具扩展性的机制.
· 效率Efficiency. 库支持发散聚合IO(scatter-gather I/O)等技术,使应用程序尽量少的拷贝数据.
· 可以像BSD Sockets一样通过API函数建立模型概念. BSD Socket API应用广为人知,有很多相关的程序库.其他编程语言通常使用其简单的网络API接口.出于这些原因, Boost.Asio同样使用已存在的技术构建.
· 易于使用Ease of use. 库提供了工具箱而不是框架来降低新手的入门门槛.可使用最少的时间投入来学习基本的规则和方针.而后,库的使用者只需要理解用到的特定函数即可.
· 基于更多的抽象.Basis for further abstraction. 库提供了高层次的抽象允许其他库的开发者进行扩展.例如,实现常用的HTTP协议.
虽然Boost.Asio一开始定位于网络通信,但其异步IO的概念已经扩展到了如串口通信,文件描述符等其他操作系统的IO操作方面.
Boost.Asio 可用于如socket等IO对象的同步或异步操作.在使用Boost.Asio前了解Boost.Asio概念图, 及与应用程序的相互集成是很有帮助的.
第一个范例,看看处理socket连接的情况.首先从同步操作开始.
应用程序 必须有一个 io_service 对象. io_service 对象负责连接应用程序与操作系统的IO服务.
boost::asio::io_service io_service;
要执行IO操作应用程序需要一个像TCP Socket的IO对象:
boost::asio::ip::tcp::socket socket(io_service);
而后执行同步连接操作,发送如下事件:
1. 应用程序 通过调用IO对象初始化连接操作:
socket.connect(server_endpoint);
2. IO对象向 io_service 提出请求.
3. io_service 调用 操作系统 功能执行连接操作.
4. 操作系统向 io_service 返回执行结果.
5. io_service 将错误的操作结果翻译为boost::system::error_code类型. error_code可与特定值进行比较,或作为boolean值检测(false表示无错误).结果再传递给 IO对象 .
6. 如果操作失败,IO对象抛出boost::system::system_error类型的异常.开始操作的代码如下所示:
boost::system::error_code ec;
socket.connect(server_endpoint, ec);
而后error_code类型的变量ec被赋予操作的结果值,但不会抛出异常.
对于异步操作,事件顺序不同.
1. 应用程序 调用 IO 对象进行连接操作:
socket.async_connect(server_endpoint, your_completion_handler);
your_completion_handler函数的签名为:
void your_completion_handler(const boost::system::error_code& ec);
执行的异步操作需要严格的函数签名.每种操作的合法形式可见参考文档.
2. IO对象请求 io_service .
3. io_service 通知 操作系统 其需要开始一个异步连接.
时序过程.(在同步情况下等待包括连接操作时间.)
4. 操作系统 指示连接操作完成, io_service 从队列中获取操作结果.
5. 应用程序 必须调用io_service::run()(或 io_service 相似的成员函数)以便于接收结果.调用io_service::run()会阻塞未完成的异步操作,因此可在启动第一个异步操作后调用这个函数.
6. 调用io_service::run()后,io_service返回一个操作结果,并将其翻译为error_code,传递到事件处理器中.
这是Boost.Asio的简单图形.更多特性可从文档中获取,如使用Boost.Asio执行其他类型的异步操作.
Boost.Asio库同时支持同步和异步操作.异步支持基于Proactor设计模式.下面讨论这种方式与同步操作及Reactor方式相比的优缺点.
现在讨论Proactor不依赖平台细节的特性.
— 异步操作 :定义一个异步执行操作,如Socket异步读写.
— 异步操作处理器 :执行异步操作并在操作完成后执行完成事件队列中的队列事件.从更高层次上说,服务端的stream_socket_service 就是一个异步操作处理器.
— 完成事件队列 :缓冲完成事件,直到被异步事件信号分离器移出队列.
— 完成句柄 :处理异步操作的结果.这是一个函数对象,通常使用boost::bind创建.
— 异步事件信号分离器 :在完成事件队列中阻塞等待事件,受信后向调用者返回完成事件.
— Proactor :调用异步事件信号分离器将事件移出队列,并为这个事件分配一个完成句柄(如调用函数对象).这个功能封装在io_service类中.
— 初始化器 : 执行特定程序代码启动异步操作.初始化器通过如basic_stream_socket等高层次接口与异步操作处理器交互,其返回stream_socket_service等类型的服务代理.
在很多平台上Boost.Asio按照Reactor来实现Proactor设计模式,如select,epoll或kqueue.相对于Proactor其实现方式如下:
— 异步操作处理器 :Reactor使用select,epoll或kqueue机制实现.如果reactor指示运行操作的资源已经就位,处理器执行异步操作并在完成事件队列中插入相应的完成句柄.
— 完成事件队列 :完成句柄的链表(如函数对象).
— 异步事件信号分离器 :在事件或条件变量上等待,直到完成事件队列中的完成句柄可用.
在Windows NT,2000,和XP系统中, Boost.Asio使用重叠IO高效实现了Proactor设计模式:
— 异步操作处理器 :由操作系统实现.操作调用如AcceptEx等重叠函数进行初始化.
— 完成事件队列 :由操作系统实现,与IO完成端口相关联.每个io_service实例对应一个IO完成端口.
— 异步事件信号分离器 :由Boost.Asio从队列中移除事件及其相关联的完成句柄.
— 可移植性Portability: 很多操作系统都提供原生的异步操作IO API(如Windows中的重叠IO),是开发者开发高性能网络应用程序的最佳选择.ASIO库可能实现了原生的异步IO.如果原生支持不可用,ASIO库可使用同步事件信号分离器实现典型的Reactor模式,如POSIX的select().
— 去除多线程并发的耦合
应用程序使用异步方式调用长时间运行的操作.但应用程序不必为增加并发而产生大量的线程.
每个连接一个线程的实现策略(仅需要同步的方式)--太多的线程会产生大量的CPU上下文切换,同步和数据移动,导致系统效率降低.异步操作通过最小化操作系统线程数量来可以避免线程上下文切换的代价--CPU是典型的有限资源,这时仅由激活的逻辑线程进行事件处理.
— 简单的应用程序同步.
异步操作完成句柄可以在已存在的单线程环境中进行设置,此时开发出来的应用程序逻辑清晰,不必涉及同步问题.
— 功能组合.
功能组合指实现高层次操作的功能,如按特定格式发送消息.每个功能的实现都是依赖于多次调用底层的读或写操作.
例如, 一个包含固定长度包头和变长包体的协议,包体长度在包头中指定.假设read_message操作由两个底层的读来实现,第一次接收包头,得到长度,第二次接收包体.
如果用异步方式来组合这些功能,可将这些异步调用连接到一起.前一个操作的完成句柄初始化下一个操作.封装链中的第一个操作的调用,使调用者不会意识到这个高层次的操作是按异步操作链的方式实现的.
按此方式可以很简单的向网路库中添加新的操作,开发出更高层次的抽象,如特定协议的功能和支持.
— 抽象复杂.
由于操作初始化和完成在时间和空间上是分离的,增加了使用异步机制开发程序的难度.而且控制流颠倒使应用程序很难调试.
— 内存占用.
在读和写过程中必须独占缓冲区空间,而后又变为不确定的,每个并发操作都需要一个独立的缓冲区.在Reactor模式中,换句话说,直到socket准备读或写时才需要缓冲区空间.
通常在每个并发操作中使用独立的对象是安全的,但并发操作中使用同一个对象就不安全了.然而如io_service 等类型可以保证并发操作中使用同一个对象也是安全的.
在多个线程中调用io_service::run()函数,就可以创建一个包含这些线程的线程池,其中的线程在异步操作完成后调用完成句柄.也可通过调用io_service::post()实现横跨整个线程池的任意计算任务来达到相同的目的.
注意所有加入io_service池的线程都是平等的,io_service可以按任意的方式向其分配工作.
这个库的特定平台实现会创建几个内部线程来模拟异步操作.同时,这些线程对库用户是不可见的.这些线程特性:
使用如下担保来实现:
因此,由库的使用者来建立和管理投递通知的线程.
Strand被定义为严格按顺序调用(如无并发调用)事件句柄的机制.使用Strand可以在多线程程序中同步执行代码而无需显式地加锁(如互斥量等).
Strand可以按如下两种方式来隐式或显式的应用:
· 仅在一个线程中调用io_service::run()意味着所有的事件句柄都执行在一个隐式的Strand下,因为io_service保证所有的句柄都在run()中被调用.
· 链接中只有一个相关的异步操作链(如半双工的HTTP)是不可能并发执行句柄的.也是隐式Strand的情况.
· 显式Strand需要创建一个io_service::strand实例.所有的事件句柄函数对象都需要使用io_service::strand::wrap()进行包装,或使用io_service::strand进行投递或分发.
在组合异步操作中,如async_read() 或 async_read_until(),如果完成句柄使用一个Strand管理,则其他所有中间句柄都要由同一个Strand来管理.这可以确保线程安全的访问所有在调用者和组合的操作中共享的对象(例如socket中的async_read(),调用者可以调用close()来取消操作).这是通过在所有中间句柄中添加一个钩子函数实现的,在执行最终句柄前调用自定义的钩子函数:
struct my_handler
void operator()() { ... }
template<class F>
void asio_handler_invoke(F f, my_handler*)
// Do custom invocation here.
// Default implementation calls f();
io_service::strand::wrap()函数生成一个新的定义了asio_handler_invoke的完成句柄,以便于Strand管理函数对象运行.
通常IO在连续的内存区域(缓冲区)内传输数据.这个缓冲区可以简单的认为是包含了一个指针地址和一些字节的东西.然而,为了高效的开发网络应用程序, Boost.Asio支持分散聚合操作,需要一个或多个缓冲区:
因此需要一个抽象概念代表缓冲区集合.为此Boost.Asio定义了一个类(实际上是两个类)来代表单个缓冲区.可存储在向分散集合操作传递的容器中.
此外可将缓冲区看做是一个具有地址和大小的字节数组, Boost.Asio区别对待可修改内存(叫做mutable)和不可修改内存(后者在带有const声明的存储区域上创建).这两种类型可以定义为:
typedef std::pair<void*, std::size_t> mutable_buffer;
typedef std::pair<const void*, std::size_t> const_buffer;
这里mutable_buffer 可以转换为const_buffer ,但反之不成立.
然而,Boost.Asio没有使用上述的定义,而是定义了两个类: mutable_buffer 和 const_buffer.目的是提供了不透明的连续内存概念:
最后将多个缓冲区存入一个容器中就可以传递给分散聚合操作了.(如 read() 或 write() ).为了使用std::vector, std::list, std::vector 或 boost::array等容器而定义了MutableBufferSequence和ConstBufferSequence概念.
类boost::asio::basic_streambuf从std::basic_streambuf继承,将输入输出流与一个或多个字符数组类型的对象相关联,其中的每个元素可以存储任意值.这些字符数组对象是内部的streambuf对象,但通过直接存取数组中的元素使其可用于IO操作,如在socket中发送或接收:
streambuf 构造函数接收一个size_t的参数指定输入序列和输出序列大小的总和.对于任何操作,如果成功,增加内部数据量,超过这个大小限制会抛出std::length_error异常.
buffers_iterator<>类模板可用于像遍历连续字节序列一样遍历缓冲区序列(如MutableBufferSequence 或 ConstBufferSequence).并提供了buffers_begin() 和 buffers_end()帮助函数, 会自动推断buffers_iterator<>的模板参数.
例如,从socket中读取一行数据,存入std::string中:
boost::asio::streambuf sb;
std::size_t n = boost::asio::read_until(sock, sb, '\n');
boost::asio::streambuf::const_buffers_type bufs = sb.data();
std::string line(
boost::asio::buffers_begin(bufs),
boost::asio::buffers_begin(bufs) + n);
有些标准库实现,如VC++8.0或其后版本,提供了叫做迭代器调试的特性.这意味着运行期会验证迭代器是否合法.如果应用程序试图使用非法的迭代器,会抛出异常.例如:
std::vector<int> v(1)
std::vector<int>::iterator i = v.begin();
v.clear(); // invalidates iterators
*i = 0; // assertion!
Boost.Asio 利用这个特性实现缓冲区调试.对于下面的代码:
void dont_do_this()
std::string msg = "Hello, world!";
boost::asio::async_write(sock, boost::asio::buffer(msg), my_handler);
当调用异步读或写时需要确保此操作的缓冲区在调用完成句柄时可用.上例中,缓冲区是std::string变量msg.变量在栈中,异步完成前已经过期了.如果幸运的话程序崩溃,但更可能会出现随机错误.
当缓冲区调试启动后,Boost.Asio会存储一个字符串的迭代器,一直保存到异步操作完成,然后解引用来检查有效性.上例中在Boost.Asio调用完成句柄前就会看到一个断言错误.
当定义_GLIBCXX_DEBUG 选项时,会自动在VS8.0及其以后版本和GCC中启动这个特性.检查需要性能代价,因此缓冲区调试只在debug生成时启用.其他编译器可通过定义BOOST_ASIO_ENABLE_BUFFER_DEBUGGING选项来启动.也可显式的通过BOOST_ASIO_DISABLE_BUFFER_DEBUGGING选项停止.
很多Boost.Asio中的IO对象都是基于流的.意味着:
提供基于流IO操作模型的对象需要模拟如下几个操作:
基于流的IO对象包括ip::tcp::socket, ssl::stream<>, posix::stream_descriptor, windows::stream_handle等等.
通常程序需要传递指定数量的字节数据.启动操作后就会发生短读或短写,直到所有数据传输完毕.Boost.Asio提供了通用函数来自动完成这些操作: read(), async_read(), write() 和 async_write().
有时应用程序必须整合第三方的库来实现IO操作.为此,Boost.Asio提供一个可用于读和写操作的null_buffers类型.null_buffers直到IO对象准备好执行操作后才会返回.
例如,如下代码执行无阻塞读操作:
ip::tcp::socket socket(my_io_service);
socket.non_blocking(true);
socket.async_read_some(null_buffers(), read_handler);
void read_handler(boost::system::error_code ec)
if (!ec)
std::vector<char> buf(socket.available());
socket.read_some(buffer(buf));
Socket在所有平台上都支持这种操作,是POSIX基于流的描述符合类.
很多常用的网络协议都是基于行的,即这些协议元素被字符序列"\r\n"限定.例如HTTP,SMTP和FTP.为了便于实现基于行的协议,以及其他使用分隔符的协议,Boost.Asio包括了read_until() 和 async_read_until()函数.
如下代码展示在HTTP服务端使用async_read_until()接收客户端的第一行HTTP请求:
class http_connection
void start()
boost::asio::async_read_until(socket_, data_, "\r\n",
boost::bind(&http_connection::handle_request_line, this, _1));
void handle_request_line(boost::system::error_code ec)
if (!ec)
std::string method, uri, version;
char sp1, sp2, cr, lf;
std::istream is(&data_);
is.unsetf(std::ios_base::skipws);
is >> method >> sp1 >> uri >> sp2 >> version >> cr >> lf;
boost::asio::ip::tcp::socket socket_;
boost::asio::streambuf data_;
Streambuf数据成员用于存储在查找到分隔符前接收的数据.记录分隔符以后的数据也是很重要的.这些保留在streambuf中的冗余数据会被保留下来用于随后调用的read_until()或async_read_until()函数进行检查.
分隔符可以是单个字符,一个std::string或一个boost::regex. read_until() 和 async_read_until()函数也可接收一个用户定义函数作为参数,获取匹配条件.例如,在streambuf中读取数据,遇到一个空白字符后停止.:
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);
从streambuf中读取数据,直到遇到匹配的字符:
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<>类型会自动的对函数,及带有嵌套result_type类型定义的函数对象的返回值值进行评估是否为true.如上例所示,其他类型的特性必须显式指定.
很多异步操作需要分配对象,用来存储与操作有关的状态数据.例如,Win32的实现中需要将重叠子对象传递给Win32 API函数.
幸好程序包含一个易于识别的异步操作链.半双工协议(如HTTP服务)为每个客户端创建一个单操作链.全双工协议实现有两个并行的执行链.程序运用这个规则可以在链上的所有异步操作中重用内存.
假设复制一个用户定义的句柄对象h,如果句柄的实现需要分配内存,应该有如下代码:
void* pointer = asio_handler_allocate(size, &h);
同样要释放内存:
asio_handler_deallocate(pointer, size, &h);
这个函数实现了参数依赖的定位查找.asio空间中有这个函数的默认实现:
void* asio_handler_allocate(size_t, ...);
void asio_handler_deallocate(void*, size_t, ...);
实现了::operator
new() 和 ::operator
delete()功能.
函数实现保证了相关句柄调用前会发生内存重新分配,这样就可以实现同一个句柄上的异步操作重用内存.
在任意调用库函数的用户线程中都可调用自定义内存分配函数.实现保证库中的这些异步操作不会并发的对句柄进行内存分配函数调用.实现要加入适当的内存间隔,保证不同线程中调用的内存分配函数有正确的内存可见性.
为调试异步程序,Boost.Asio提供了句柄跟踪支持.当激活BOOST_ASIO_ENABLE_HANDLER_TRACKING定义,Boost.Asio向标准错误流中写入调试输出信息.输出信息记录异步操作及其句柄间的关系.
这个特性对调试很有帮助,需要知道异步操作是如何被链接在一起的,或什么异步操作被挂起了.如下是HTTP服务输出的调试信息,处理单个请求,而后按Ctrl+C退出:
@asio|1298160085.070638|0*1|signal_set@0x7fff50528f40.async_wait
@asio|1298160085.070888|0*2|socket@0x7fff50528f60.async_accept
@asio|1298160085.070913|0|resolver@0x7fff50528e28.cancel
@asio|1298160118.075438|>2|ec=asio.system:0
@asio|1298160118.075472|2*3|socket@0xb39048.async_receive
@asio|1298160118.075507|2*4|socket@0x7fff50528f60.async_accept
@asio|1298160118.075527|<2|
@asio|1298160118.075540|>3|ec=asio.system:0,bytes_transferred=122
@asio|1298160118.075731|3*5|socket@0xb39048.async_send
@asio|1298160118.075778|<3|
@asio|1298160118.075793|>5|ec=asio.system:0,bytes_transferred=156
@asio|1298160118.075831|5|socket@0xb39048.close
@asio|1298160118.075855|<5|
@asio|1298160122.827317|>1|ec=asio.system:0,signal_number=2
@asio|1298160122.827333|1|socket@0x7fff50528f60.close
@asio|1298160122.827359|<1|
@asio|1298160122.827370|>4|ec=asio.system:125
@asio|1298160122.827378|<4|
@asio|1298160122.827394|0|signal_set@0x7fff50528f40.cancel
每行的格式为:
<tag>|<timestamp>|<action>|<description>
<tag>一直是@asio,用于在程序输出中识别和提取句柄跟踪消息.
<timestamp>
是从UTC时间1970年一月一日起至今的秒数.
<action>
有如下几种形式:
程序进入了第n个句柄.<description>描述句柄参数.
程序退出第n个句柄.
程序由于异常退出第n个句柄.
第n个句柄没有执行就被销毁了.通常是由于io_service销毁时异步操作还没有完成.
第n个句柄创建了一个生成第m个完成句柄的新异步操作.<description>描述什么异步操作被启动.
第n个句柄执行其他操作.<description>显示调用了哪些函数.通常只记录close()和cancel()操作,因为其影响了异步操作挂起状态.
当<description>显示同步或异步操作,格式为
<object-type>@<pointer>.<operation>
. 并以逗号间隔来显示执行句柄的参数和值.
如上所示,每个句柄都由唯一的数字进行标识.句柄跟踪输出的句柄编号是0的,表示操作不是这些句柄执行的.
句柄跟踪输出可以使用包含在
handlerviz.pl
中的工具进行处理,创建可视化的界面.
Boost.Asio 对TCP,UDP和ICMP提供了完整的支持.
使用resolver执行主机名称解析,查询主机和服务名称并转换为一个或多个端点:
ip::tcp::resolver resolver(my_io_service);
ip::tcp::resolver::query query("www.boost.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连接成功为止.例如,简单的调用:
ip::tcp::socket socket(my_io_service);
boost::asio::connect(socket, resolver.resolve(query));
将同时尝试所有端点直到找到连接成功.同样异步操作的方式为:
boost::asio::async_connect(socket_, iter,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
// ...
void handle_connect(const error_code& error)
if (!error)
// Start read or write operations.
// Handle error.
当特定端点可用,socket创建并连接.方式为:
ip::tcp::socket socket(my_io_service);
socket.connect(endpoint);
使用成员函数 receive() , async_receive() , send() 或 async_send() 可将数据读于或写到TCP连接的Socket上.然而为了快速的读写操作,通常使用 read() , async_read() , write() 和 async_write() 函数进行操作.
程序使用接收器来接收到达的TCP连接:
ip::tcp::acceptor acceptor(my_io_service, my_endpoint);
ip::tcp::socket socket(my_io_service);
acceptor.accept(socket);
当成功接收一个socket连接(向如上例中的TCP客户端),就可以在其上读取或写入数据了.
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绑定到了本地端点.如下代码创建一个IPv4的UDP Socket,绑定到任意地址的12345端口上:
ip::udp::endpoint endpoint(ip::udp::v4(), 12345);
ip::udp::socket socket(my_io_service, endpoint);
使用成员函数 receive_from() , async_receive_from() , send_to() 或 async_send_to() 可在无连接的UPD Socket上读出或写入数据.对于连接的UDP Socket,可使用 receive() , async_receive() , send() 或 async_send() 成员函数.
如同TCP和UPD一样,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() 在无连接的ICMP上读出或写入数据.
其他Socket协议的支持(如蓝牙或IRCOMM)可按协议要求进行实现.
Boost.Asio 中包含一个在Socket上实现的iostream类.将端点解析,协议无关等复杂特性的实现隐藏起来.要创建连接只需简单的写几行代码:
ip::tcp::iostream stream("www.boost.org", "http");
if (!stream)
// Can't connect.
iostream 类可以与接收器一起创建简单的服务端.例如:
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()函数设置超时期限.超时的Socket操作会将iostream设置为"bad"状态.
例如,一个简单的客户端程序:
ip::tcp::iostream stream;
stream.expires_from_now(boost::posix_time::seconds(60));
stream.connect("www.boost.org", "http");
stream << "GET /LICENSE_1_0.txt HTTP/1.0\r\n";
stream << "Host: www.boost.org\r\n";
stream << "Accept: */*\r\n";
stream << "Connection: close\r\n\r\n";
stream.flush();
std::cout << stream.rdbuf();
如果所有的Socket操作时间加起来超过60秒则失败.
如果发生错误,可使用iostream的error()成员函数获取最近系统操作的错误码:
if (!stream)
std::cout << "Error: " << stream.error().message() << "\n";
这个iostream模板只支持char,不支持wchar_t,不要用于这样的代码版本.
Boost.Asio 包含了实现BSD Socket API的低层次Socket接口的库.在其他语言中后者也作为最基本的网络API,如Java.底层次接口可用来开发高效率和高可伸缩性的应用程序.例如,程序员可以更好的控制系统调用次数,避免基础数据拷贝,最小化如线程等资源的使用等.
BSD Socket API包含了不安全和有错误倾向的方面.例如,使用整型数字代表socket缺乏安全性. Boost.Asio 中使用不同的Socket类型代表不用的协议,如TCP对应的是ip::tcp::socket,UDP对应的ip::udp::socket.
下表是BSD Socket API和Boost.Asio的对比:
TCP: ip::tcp::acceptor::close() , ip::tcp::socket::close()
getaddrinfo(), gethostbyaddr(), gethostbyname(), getnameinfo(), getservbyname(), getservbyport()
TCP: ip::tcp::resolver::resolve() , ip::tcp::resolver::async_resolve()
UDP: ip::udp::resolver::resolve() , ip::udp::resolver::async_resolve()
ip::basic_resolver::resolve() , ip::basic_resolver::async_resolve()
TCP: ip::tcp::acceptor::local_endpoint() , ip::tcp::socket::local_endpoint()
UDP: ip::udp::socket::local_endpoint()
basic_socket::local_endpoint()
TCP: ip::tcp::acceptor::get_option() , ip::tcp::socket::get_option()
UDP: ip::udp::socket::get_option()
io_service::run() , io_service::run_one() , io_service::poll() , io_service::poll_one()
注意:包括异步操作.
CP: ip::tcp::socket::read_some() , ip::tcp::socket::async_read_some() , ip::tcp::socket::receive() , ip::tcp::socket::async_receive()
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()
TCP: ip::tcp::socket::write_some() , ip::tcp::socket::async_write_some() , ip::tcp::socket::send() , ip::tcp::socket::async_send()
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()
TCP: ip::tcp::acceptor::set_option() , ip::tcp::socket::set_option()
UDP: ip::udp::socket::set_option()
长时间运行的操作通常都会设置一个最终的完成期限.这个最终期限可以是使用绝对时间来表示,但通常使用相对时间.
一个简单的范例,在相对时间内执行等待异步操作:
io_service i;
deadline_timer t(i);
t.expires_from_now(boost::posix_time::seconds(5));
t.wait();
通常,程序会基于计时器来执行异步等待操作:
void handler(boost::system::error_code ec) { ... }
io_service i;
deadline_timer t(i);
t.expires_from_now(boost::posix_time::milliseconds(400));
t.async_wait(handler);
i.run();
定时器相关联的超时期限可以是相对时间:
boost::posix_time::time_duration time_until_expiry
= t.expires_from_now();
或使用绝对时间:
deadline_timer t2(i);
t2.expires_at(t.expires_at() + boost::posix_time::seconds(30));
Boost.Asio包含用灵活的方式创建和操作串口的类.例如,打开串口的代码:
serial_port port(my_io_service, name);
name是如Windows中的"COM1",及POSIX平台下的"/dev/ttyS0".
打开后,串口就可以向流一样使用了.既这个对象可以用于 async_read() , write() , async_write() , read_until() 或 async_read_until() 函数.
串口实现中还包括配置串口波特率,流控制,奇偶校验,停止位和字符数量等可选类.
串口可用于所有POSIX平台.Windows中串口通信需要在编译期将IO完成端口激活.程序可以测试BOOST_ASIO_HAS_SERIAL_PORTS宏来检查Windows系统是否支持串口操作.
Boost.Asio通过signal_set类实现信号处理.程序可以向集合中加入一个或多个信号,而后执行asyn_wait()操作.当其中一个信号发生时执行特定的事件处理函数.同一个信号可注册在多个singal_set对象中,但这些信号只能用于Boost.Asio .
void handler(
const boost::system::error_code& error,
int signal_number)
if (!error)
// A signal occurred.
// Construct a signal set registered for process termination.
boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(handler);
信号处理也可在Windows中使用,与VC++运行时库映射到控制台的事件如Ctrl+C等价.
Boost.Asio 提供了UNIX领域的Socket基本支持(又叫做本地Socket).最简单的使用情况是有一对连接Socket.代码如下:
local::stream_protocol::socket socket1(my_io_service);
local::stream_protocol::socket socket2(my_io_service);
local::connect_pair(socket1, socket2);
将创建一对基于流的Socket.要实现基于数据包的Socket,使用:
local::datagram_protocol::socket socket1(my_io_service);
local::datagram_protocol::socket socket2(my_io_service);
local::connect_pair(socket1, socket2);
UNIX领域的Socket服务可以创建在一个绑定一个端点的接收器上,TCP服务也类似:
::unlink("/tmp/foobar"); // Remove previous binding.
local::stream_protocol::endpoint ep("/tmp/foobar");
local::stream_protocol::acceptor acceptor(my_io_service, ep);
local::stream_protocol::socket socket(my_io_service);
acceptor.accept(socket);
客户端连接到服务端代码:
local::stream_protocol::endpoint ep("/tmp/foobar");
local::stream_protocol::socket socket(my_io_service);
socket.connect(ep);
Boost.Asio不支持跨UNIX领域Socket传输文件描述符或证书,但可以使用native()函数调用Socket的底层描述符来实现.
UNIX领域的Socket仅在支持的平台上编译的时候激活.可以测试BOOST_ASIO_HAS_LOCAL_SOCKETS宏检查是否支持.
Boost.Asio 包含在POSIX文件描述符上同步或异步读写的类,如管道,标准输入输出,和各种设备(但不是常规的文件).
例如,在标准输入输出上执行读写,创建如下对象:
posix::stream_descriptor in(my_io_service, ::dup(STDIN_FILENO));
posix::stream_descriptor out(my_io_service, ::dup(STDOUT_FILENO));
而后进行同步或异步读写流.即对象可用于 read() , async_read() , write() , async_write() , read_until() 或 async_read_until() 等函数.
POSIX流描述符仅在支持平台上编译时激活.程序可以检查BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR宏查询是否支持.
Boost.Asio 支持程序使用fork()系统调用.程序可以在适当时间调用io_service.notify_fork(),Boost.Asio可重新创建一个内部的文件描述符(如使用"self-pipe trick"描述符技巧激活反应器(reactor)).通知用法如下:
io_service_.notify_fork(boost::asio::io_service::fork_prepare);
if (fork() == 0)
io_service_.notify_fork(boost::asio::io_service::fork_child);
io_service_.notify_fork(boost::asio::io_service::fork_parent);
用户定义服务可以重写io_service::service::fork_service()虚函数有意制造fork操作.
注意所有Boost.Asio的公共API函数可访问的文件描述符(如basic_socket<>, posix::stream_descriptor下的描述符)在fork期间不会更改.这需要程序按需要进行管理.
Boost.Asio 包含允许在Windows句柄上执行异步读或写操作的类,如命名管道.
例如,在命名管道上执行异步操作,创建如下对象:
HANDLE handle = ::CreateFile(...);
windows::stream_handle pipe(my_io_service, handle);
而后使用同步或异步方式读写流.即对象可用于 read() , async_read() , write() , async_write() , read_until() 或 async_read_until() 函数.
句柄相对的内核对象必须支持IO完成端口(命名管道支持,但匿名管道和控制台流不支持).
Windows句柄流只能在编译期激活,而且必须只用IO完成端口作为后台处理(默认).可使用BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE宏检测.
Boost.Asio提供特定的类实现在规则文件相关句柄上执行异步读写操作.
例如,在文件上执行异步操作代码:
HANDLE handle = ::CreateFile(...);
windows::random_access_handle file(my_io_service, handle);
可以通过成员函数read_some_at(), async_read_some_at(), write_some_at() 或 async_write_some_at()来读出或写入数据.然而,和流上的等价函数(read_some()等)一样,这些函数只需要在单个操作中传递一个或多个字节.因此创建了
read_at()
,
async_read_at()
,
write_at()
和
async_write_at()
函数,内部重复调用相应的
*
_some_at()
函数直到所有数据传递完毕为止.
Windows随机读取句柄只能在编译期激活,而且后台使用IO完成端口进行处理才可用.可使用BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE宏来检测.
Boost.Asio提供Windows特有的类实现在内核对象句柄上进行异步等待的操作:
例如,在事件上执行异步操作,创建如下对象:
HANDLE handle = ::CreateEvent(...);
windows::object_handle file(my_io_service, handle);
wait()和async_wait()成员函数用于等待内核对象受信.
Windows对象句柄需要在编译期激活.可使用BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE宏检查.
Boost.Asio 包括对SSL支持的类和类模板.这些类可以在通信时将已存在的流(如TCP Socket)进行加密.
在创建加密流前,应用程序必须构造SSL上下文对象.这个对象中通常设置了如验证模式,证书文件等SLL选项.例如,客户端初始化代码如下:
ssl::context ctx(ssl::context::sslv23);
ctx.set_verify_mode(ssl::verify_peer);
ctx.load_verify_file("ca.pem");
在TCP Socket下使用SSL:
ssl::stream<ip::tcp::socket> ssl_sock(my_io_service, ctx);
执行特定的Socket操作,如建立远程连接或接收连接,底层的Socket必须使用ssl::stream模板的lowest_layer()成员函数来获取:
ip::tcp::socket::lowest_layer_type& sock = ssl_sock.lowest_layer();
sock.connect(my_endpoint);
有时底层的流对象的生命期要比SSL流长,这时模板参数需要引用流类型:
ip::tcp::socket sock(my_io_service);
ssl::stream<ip::tcp::socket&> ssl_sock(sock, ctx);
SSL的加密连接握手需要在传输或接收数据前进行.可通过ssl::stream模板的handshake()或async_handshake()成员函数建立连接.
连接后,SSL流对象即可向同步或异步读写流一样的方式使用了.即对象可用于 read() , async_read() , write() , async_write() , read_until() 或 async_read_until() 函数.
Boost.Asio 提供各种方法来配置SSL证书验证:
简单情况下证书验证规则为RFC2818(HTTPS下证书验证), Boost.Asio 提供一个可重用的证书验证回调函数对象:
下例演示用HTTPS的方式验证远程主机的证书:
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<tcp::socket> ssl_socket;
// Create a context that uses the default paths for
// finding CA certificates.
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Open a socket and connect it to the remote host.
boost::asio::io_service io_service;
ssl_socket sock(io_service, ctx);
tcp::resolver resolver(io_service);
tcp::resolver::query query("host.name", "https");
boost::asio::connect(sock.lowest_layer(), resolver.resolve(query));
sock.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certificate.
sock.set_verify_mode(ssl::verify_peer);
sock.set_verify_callback(ssl::rfc2818_verification("host.name"));
sock.handshake(ssl_socket::client);
// ... read and write as normal ...
SSL流对象在无锁定的情况下执行.因此,异步执行SSL都需要隐式或显式的应用strand.注意这意味着在单线程程序中不需同步控制(不必使用锁).
OpenSSL需要Boost.Asio的SSL支持.当应用程序使用未由Boost.Asio包装的OpenSSL功能时,底层的OpenSSL类可通过调用 ssl::context::native_handle() 或 ssl::stream::native_handle() 获得.
C++支持移动对象后(通过右值引用),Boost.Asio可以对socket,串口,POSIX描述符和Windows句柄进行移动构造和赋值.
通过移动对象可实现如下代码:
tcp::socket make_socket(io_service& i)
tcp::socket s(i);
std::move(s);
class connection : public enable_shared_from_this<connection>
private:
tcp::socket socket_;
public:
connection(tcp::socket&& s) : socket_(std::move(s)) {}
class server
private:
tcp::acceptor acceptor_;
tcp::socket socket_;
void handle_accept(error_code ec)
if (!ec)
std::make_shared<connection>(std::move(socket_))->go();
acceptor_.async_accept(socket_, ...);
std::vector<tcp::socket> sockets;
sockets.push_back(tcp::socket(...));
一字真言:当异步操作挂起时是可以继续移动对象的,但这不是一个好主意.特别是操作由如async_read()等函数触发时其引用了流对象.在操作期间移动对象将会导致相应操作访问已移动的对象.
移动支持在g++4.5及以后版本加入
-std=c++0x
或
-std=gnu++0x
编译选项即可自动支持.可通过BOOST_ASIO_DISABLE_MOVE定义宏禁用或BOOST_ASIO_HAS_MOVE宏激活.注意这些宏还会影响可移动句柄.
优化后,用户定义的完成句柄可支持移动构造,Boost.Asio的实现会优先于拷贝构造函数使用移动构造函数.当前环境下,Boost.Asio也可能去除所有句柄的拷贝构造函数.然而,句柄类型还是需要拷贝构造函数的.
当激活移动支持,异步代码为:
template <typename Handler>
void async_XYZ(..., Handler handler);
实际上声明为:
template <typename Handler>
void async_XYZ(..., Handler&& handler);
句柄参数在async_XYZ函数体内部完美的传递,并发生了移动构造.这可确保函数的所有其他参数都会提前评估移动.尤其是在async_XYZ()的其他参数为句柄的成员时更重要.例如:
struct my_operation
shared_ptr<tcp::socket> socket;
shared_ptr<vector<char>> buffer;
void operator(error_code ec, size_t length)
socket->async_read_some(boost::asio::buffer(*buffer), std::move(*this));
移动支持在g++4.5及以后版本加入
-std=c++0x
或
-std=gnu++0x
编译选项即可自动支持.可通过BOOST_ASIO_DISABLE_MOVE定义宏禁用或BOOST_ASIO_HAS_MOVE宏激活.注意这些宏还会影响可移动IO对象.
如果编译器支持,Boost.Asio可以使用可变参模板实现 basic_socket_streambuf::connect() 和 basic_socket_iostream::connect() 函数.
可变参模板支持在g++4.3及以后版本中的编译期添加
-std=c++0x
或
-std=gnu++0x
编译选项会自动激活.可使用BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES宏禁用,使用BOOST_ASIO_HAS_VARIADIC_TEMPLATES宏激活.
由于标准库提供了std::array<>,Boost.Asio:
G++4.3及以后版本中加上
-std=c++0x
或
-std=gnu++0x
编译选项即可自动激活std::array<>,同时VC++10也支持.使用BOOST_ASIO_DISABLE_STD_ARRAY宏禁用,或BOOST_ASIO_HAS_STD_ARRAY宏激活.
Boost.Asio的实现相对于boost::detail::atomic_count优先使用std::atomic<>.
在g++4.5及以后版本中加入
-std=c++0x
或
-std=gnu++0x
编译选项即可激活标准的原语整数模板.可使用BOOST_ASIO_DISABLE_STD_ATOMIC宏禁用,或BOOST_ASIO_HAS_STD_ATOMIC宏启用.
Boost.Asio 优先使用std::shared_ptr<>和std::weak_ptr<>.
Boost.Asio基于std::chrono机制通过 basic_waitable_timer 类模板提供了基本的定时器功能. system_timer , steady_timer 和 high_resolution_timer 分别使用system_clock, steady_clock 和 high_resolution_clock标准时钟.
g++4.6级以后版本添加
-std=c++0x
或
-std=gnu++0x
编译选项即可自动支持std::chrono.(注意,g++中使用monotonic_clock替代steady_clock.)使用BOOST_ASIO_DISABLE_STD_CHRONO宏禁用, BOOST_ASIO_HAS_STD_CHRONO宏激活.
如果chrono不可用,可使用Boost.Chrono库. basic_waitable_timer 类仍可用.
在如下平台和编译器下测试通过:
也可用于如下平台:
为使程序可连接到Boost.Asio如下库必须可用:
而且有些范例需要Boost.Thread, Boost.Date_Time 或 Boost.Serialization库的支持.
可以按需要生成Boost的子库,下例在Boost的根目录中运行命令行:
bjam --with-system --with-thread --with-date_time --with-regex --with-serialization stage
这里假设已经生成了bjam.更多信息见Boost.Build文档.
默认情况下,Boost.Asio仅是一个有头文件的库.然而,有些开发者更愿意分开编译Boost.Asio的源码.只需要在程序的源文件中加入#include
<boost/asio/impl/src.hpp>,而后在项目/编译器设置中加入BOOST_ASIO_SEPARATE_COMPILATION编译选项并进行编译.或者使用BOOST_ASIO_DYN_LINK选项将Boost.Asio独立编译为静态库.
如果使用Boost.Asio的SSL支持,需要加入#include
<boost/asio/ssl/impl/src.hpp>.
下表中的宏可用来控制Boost.Asio的行为.
激活Boost.Asio的缓冲区调试支持,可帮助识别出在读写中引用的无效缓冲区(例如,向std::string写数据,但在操作完成前就已经被释放了).
在Microsoft Visual C++中,如果激活编译器的迭代调试支持这个宏会自动定义,否则需要定义BOOST_ASIO_DISABLE_BUFFER_DEBUGGING.
在G++中,如果启动标准库调试(定义了_GLIBCXX_DEBUG宏)这个宏会自动定义,否则需要定义BOOST_ASIO_DISABLE_BUFFER_DEBUGGING 宏.
When compiling for Windows using Microsoft Visual C++ or Borland C++, Boost.Asio will automatically link in the necessary Windows SDK libraries for sockets support (i.e.
ws2_32.lib
and
mswsock.lib
, or
ws2.lib
when building for Windows CE). The BOOST_ASIO_NO_DEFAULT_LINKED_LIBS macro prevents these libraries from being linked.
Enables use of the CancelIo function on older versions of Windows. If not enabled, calls to cancel() on a socket object will always fail with asio::error::operation_not_supported when run on Windows XP, Windows Server 2003, and earlier versions of Windows. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used.
The CancelIo function has two issues that should be considered before enabling its use:
* It will only cancel asynchronous operations that were initiated in the current thread.
* It can appear to complete without error, but the request to cancel the unfinished operations may be silently ignored by the operating system. Whether it works or not seems to depend on the drivers that are installed.
For portable cancellation, consider using one of the following alternatives:
* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP.
* Use the socket object's close() function to simultaneously cancel the outstanding operations and close the socket.
Determines the number of buckets in Boost.Asio's internal hash_map objects. The value should be a comma separated list of prime numbers, in ascending order. The hash_map implementation will automatically increase the number of buckets as the number of elements in the map increases.
Some examples:
* Defining BOOST_ASIO_HASH_MAP_BUCKETS to 1021 means that the hash_map objects will always contain 1021 buckets, irrespective of the number of elements in the map.
* Defining BOOST_ASIO_HASH_MAP_BUCKETS to 53,389,1543 means that the hash_map objects will initially contain 53 buckets. The number of buckets will be increased to 389 and then 1543 as elements are added to the map.
Boost.Asio 的邮件列表可从
SourceForge.net
查找.新闻组见
Gmane
.
用户通常受益于Boost.Asio WIKI上的共享范例,提示和FAQ.,请见
http://think-async.com/Asio/
.
入门教程的第一小节介绍使用asio工具的基本概念.在开发复杂的网络程序前,范例程序阐述使用异步定时器的基本技巧.
Timer.1 - Using a timer synchronously
同步定时程序
Timer.2 - Using a timer asynchronously
异步定时程序
Timer.3 - Binding arguments to a handler
向处理函数绑定参数
Timer.4 - Using a member function as a handler
使用成员函数作为处理函数
Timer.5 - Synchronising handlers in multithreaded programs
多线程程序中的处理函数同步
Sockets简介
本节教程展示如何使用asio开发一个简单的客户端和服务端程序.程序使用TCP和UDP实现了基本的daytime协议.
前面三个程序使用TCP实现daytime协议.
Daytime.1 - A synchronous TCP daytime client
Daytime.2 - A synchronous TCP daytime server
Daytime.3 - An asynchronous TCP daytime server
后面三个程序使用UDP实现daytime协议.
Daytime.4 - A synchronous UDP daytime client
Daytime.5 - A synchronous UDP daytime server
Daytime.6 - An asynchronous UDP daytime server
本节最后的程序展示如何在一个程序中使用asio来组合TCP和UDP服务.
Daytime.7 - A combined TCP/UDP asynchronous server
定时器1-使用同步定时器
本教程演示如何使用asio的定时器执行阻塞等待.
需要包含必要的头文件:
简单的包含"asio.hpp"头文件即可使用所有的asio类.
#include <iostream>
#include <boost/asio.hpp>
由于本例使用了定时器,需要包含相应的Boost.Date_Time头文件以便于操作定时器.
#include <boost/date_time/posix_time/posix_time.hpp>
所有使用asio的程序都要创建一个io_service对象.这个类提供IO功能支持.在main函数中首先声明这个类的对象.
int main()
boost::asio::io_service io;
接着声明一个boost::asio::deadline_timer类型的对象.这些提供IO功能的核心asio类 (或是定时器功能)构造函数的第一个参数总是io_service类的实例.第二个参数设置过期时间为从现在起5秒钟以后.
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
这是在定时器上阻塞等待的简单范例.调用
deadline_timer::wait()
会在定时器到期(5秒钟)后才返回.
定时器总是有两个状态: "到期" 或 "未到期".如果
deadline_timer::wait()
函数在一个已过期的时间上执行,会立即返回.
t.wait();
最后在时间到期后输出著名的"Hello, world!"消息.
std::cout << "Hello, world!\n";
return 0;
定时器2--异步使用定时器
本范例修改了time1范例,通过在定时器上异步等待演示了如何使用asio异步回调功能.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
使用asio的异步功能意味着需要定义一个回调函数,在异步操作完成后执行.本程序中定义了一个叫做print的函数,异步等待完成后调用.
void print(const boost::system::error_code& /*e*/)
std::cout << "Hello, world!\n";
int main()
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
接下来,替换范例1中的阻塞等待.调用
deadline_timer::async_wait()
函数执行异步等待.在这个函数中传递了上面定义的print回调函数.
t.async_wait(&print);
最后,必须在io_service对象上调用io_service::run()成员函数.
Asio库保证回调函数在调用了io_service::run()的线程上执行.因此只有调用了io_service::run()函数,异步等待完成的回调函数才能被调用.
Io_service::run()将会一直在运行,因为其还有工作要做.本例中,这个工作是异步等待定时器,因此直到定时器过期而且回调函数执行完毕,才会退出.
在调用io_service::run()前为其指定工作是很重要的.例如,如果上例中忘记调用
deadline_timer::async_wait()
,io_service无事可做,则io_service::run()调用会立即返回.
io.run();
return 0;
定时器3-向处理器传递参数
本程序从Timer2程序修改而来,将timer改为每秒触发一次.用来阐述如何向处理函数传递其他参数.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
为了让timer循环的过期,需要在回调函数中修改timer的过期时间,而后开始一个新的异步等待.当然必须让回调函数可以访问到timer对象.要实现这个效果需要向print函数传递两个参数:
指向timer对象的指针.
Timer触发计数器,以便于实现触发6次后结束程序运行.
void print(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t, int* count)
如上所述,程序使用计时器来停止运行,如果定时器触发测试超过6次则退出.然而这里并没有显式的让io_service停止运行.在定时器2范例中我们知道,只有无事可做时io_service::run()才会退出.当计数器等于5时就不在启动新的异步等待,则io_service完成了工作并停止运行.
if (*count < 5)
std::cout << *count << "\n";
++(*count);
另外将过期时间从前一个过期时间向后延迟一秒.在原来基础上定义新的过期时间,可以确保定时器标记的秒数不会由于处理函数执行而延时.
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
而后在timer上启动一个新的异步等待.boost::bind()函数用来将回调函数与参数相关联.
deadline_timer::async_wait()
函数希望的回调函数形式为void(const
boost::system::error_code&).bind函数将回调函数print连同附加的参数转换为这种正确的函数签名.
更多Boost.Bind信息见
Boost.Bind documentation
.
本例中,boost::bind()的boost::asio::placeholders::error参数是传递给成了函数的错误对象名称占位符.如果使用boost::bind()初始化异步操作,必须指定与句柄参数列表相一致的参数.在范例4中回调函数不需要这个参数会省略掉.
t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
int main()
boost::asio::io_service io;
添加一个新的count变量,以便于在timer触发6次后结束程序运行.
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
如步骤4,在main函数中调用了
deadline_timer::async_wait()
时会向print函数传递附加参数.
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));
io.run();
最后,验证print句柄函数中的count变量,输出其值.
std::cout << "Final count is " << count << "\n";
return 0;
定时器4 -使用成员函数作为处理器
本例演示如何将类的成员函数作为回调处理函数.程序功能与Timer3完全一样.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
上一个范例中使用print函数作为回调处理函数,本例中首先定义一个printer类.
class printer
public:
类的构造函数中有个io_service的引用,用来初始化timer_成员.关闭程序的计时器也声明为类的成员.
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
Boost::bind()函数也可用于处理类的成员函数.由于所有的非静态类成员函数都有一个隐式的this参数,我们需要将this绑定到函数上.与Timer3范例一样,使用boost::bind()转换回调处理函数,将其处理为void(const
boost::system::error_code&)形式的签名.
注意这里boost::asio::placeholders::error占位符被忽略,成员函数print不在接收错误对象参数.
timer_.async_wait(boost::bind(&printer::print, this));
在类的析构函数输出最终的计数器值.
~printer()
std::cout << "Final count is " << count_ << "\n";
成员函数print与上例的print函数非常类似.由于计数器和timer都做为了类的成员,因此不必在进行参数传递了.
void print()
if (count_ < 5)
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
private:
boost::asio::deadline_timer timer_;
int count_;
Main函数与上例也很相似,现在声明一个printer对象并运行io_service.
int main()
boost::asio::io_service io;
printer p(io);
io.run();
return 0;
同步TCP daytime客户端
本例展示如何使用asio实现一个TCP客户端.
需要包含如下头文件.
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
程序的目的是要访问daytime服务器,因此需要用户指定一个服务器.
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
if (argc != 2)
std::cerr << "Usage: client <host>" << std::endl;
return 1;
所有使用asio的程序都需要一个
io_service
对象.
boost::asio::io_service io_service;
我们需要将程序参数中指定的服务器名称转换为TCP端点,因此需要定义一个
ip::tcp::resolver
对象.
tcp::resolver resolver(io_service);
分析器使用一个查询对象并获取一个端点列表.使用服务器的名称(参数argv[1])以及服务名称(本例中是daytime)作为参数来构造查询对象.
tcp::resolver::query query(argv[1], "daytime");
返回的端点列表为
ip::tcp::resolver::iterator
类型的迭代器.
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
现在创建并连接Socket.上述的端点列表可能包括IPv4或IPv6类型的端点,需要尝试每种可能获取可用的端点.这样客户端就独立于IP版本号了. boost::asio::connect()自动完成这些功能.
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
连接已经打开.现在就可以从服务端读取数据了.
使用boost::array 来接收数据. boost::asio::buffer()函数自动管理数组大小以防止缓冲区溢出.除了boost::array ,还可以使用char[]或std::vector.
for (;;)
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
当服务端关闭了连接,
ip::tcp::socket::read_some()
函数接收到boost::asio::error::eof 错误信息,退出客户端循环.
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
std::cout.write(buf.data(), len);
最后处理可能抛出的异常.
catch (std::exception& e)
std::cerr << e.what() << std::endl;
TCP daytime同步服务器
本例阐述如何使用asio实现TCP服务端应用程序.
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
定义一个make_daytime_string()函数生成发送给客户端的字符串.这个函数在所有daytime服务应用程序中重用.
std::string make_daytime_string()
using namespace std; // For time_t, time and ctime;
time_t now = time(0);
return ctime(&now);
int main()
boost::asio::io_service io_service;
ip::tcp::acceptor
对象用来侦听新到的连接.这里初始化为使用IPv4协议来侦听13端口.
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
这是个可迭代的服务端,即每次只能处理一个连接.对每个客户端链接创建一个Socket,而后等待新到来的连接.
for (;;)
tcp::socket socket(io_service);
acceptor.accept(socket);
客户端访问我们服务端.当前的时间将传递给客户端.
std::string message = make_daytime_string();
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
最后处理异常.
catch (std::exception& e)
std::cerr << e.what() << std::endl;
return 0;
异步TCP daytime服务端
main函数
int main()
首先创建一个服务对象接收客户端的连接.
io_service
对象提供IO服务,如socket就使用这个IO服务对象.
boost::asio::io_service io_service;
tcp_server server(io_service);
运行
io_service
对象使其执行异步操作.
io_service.run();
catch (std::exception& e)
std::cerr << e.what() << std::endl;
return 0;
tcp_server 类
class tcp_server
public:
构造函数初始化接收器监听TCP的13端口.
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
start_accept();
private:
函数start_accept()创建一个Socket并初始化为异步接收操作,等待新的连接.
void start_accept()
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
由start_accept()函数初始化的异步接收操作完成后会调用handle_accept()函数.其响应客户端的请求并再次调用start_accept()函数初始化下一次接收操作.
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
if (!error)
new_connection->start();
start_accept();
Tcp连接类
使用shared_ptr和enable_shared_from_this保证tcp_connetion在有相应操作期间保持激活状态.
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
return pointer(new tcp_connection(io_service));
tcp::socket& socket()
return socket_;
在函数start()中调用boost::asio::async_write()向客户端写数据.注意使用的是boost::asio::async_write()而不是
ip::tcp::socket::async_write_some()
,这样可以确保发送全部的数据.
void start()
发送的数据存储在类成员message_中,在异步操作完成前必须保证数据的有效性.
message_ = make_daytime_string();
初始化异步操作后,使用boost::bind()传递的参数必须与事件处理函数参数列表相匹配.本例中, boost::asio::placeholders::error 和 boost::asio::placeholders::bytes_transferred参数占位符都被去掉了,因为他们没有在handle_write()中使用.
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
再次处理客户端连接请求需要由handle_write()负责.
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
tcp::socket socket_;
std::string message_;
移除无用的事件处理函数的参数
你可能发现error和bytes_transferred参数在函数handle_write()中是无用的.如果参数不需要可将其移除:
void handle_write()
boost::asio::async_write()的调用调整为如下形式:
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this()));
DDaytime4-同步UDP daytime客户端
本范例程序展示如何使用asio来实现UPD客户端程序.
#include/span> <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;;
启动程序的方式和TCP daytime客户端相同.
int/span> main(int argc, char* argv[])
if (argc != 2)
std::cerr << "Usage: client <host>" << std::endl;
return 1;
boost::asio::io_service io_service;;
向
ip::udp::resolver
传递主机和服务名称获取正确的远程端点.查询通过
ip::udp::v4()
参数限制使其返回一个IPv4协议的端点.
udp::resolver resolver(io_service);
udp::resolver::query query(udp::v4(), argv[1], "daytime"));
ip::udp::resolver::resolve()
函数保证如果查询成功的话会返回至少有一个端点的列表.因此可以安全的直接对返回值进行解引用.
udp::endpoint receiver_endpoint = *resolver.resolve(query));
由于UDP是基于数据报的,没有使用基于流的Socket.创建一个
ip::udp::socket
并使用远程端点进行初始连接.
udp::socket socket(io_service);
boost::array<char, 1> send_buf = {{ 0 }};
socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint));
现在需要准备好接收服务端发送过来的数据.客户端接收服务端响应的端点要通过
ip::udp::socket::receive_from()
指定.
boost::array<char, 128> recv_buf;
udp::endpoint sender_endpoint;
size_t len = socket.receive_from(
boost::asio::buffer(recv_buf), sender_endpoint);
std::cout.write(recv_buf.data(), len);
catch (std/span>::exception& e)
std::cerr << e.what() << std::endl;
Daytime5- daytime同步UDP服务端
本范例程序展示如何使用asio实现同步UDP服务程序.
int main()
boost::asio::io_service io_service;
创建ip::udp::socket对象接收UDP 13端口上的请求.
udp::socket socket(io_service, udp::endpoint(udp::v4(), 13));
等待客户端请求连接.remote_endpoint对象将传入
ip::udp::socket::receive_from()
函数.
for (;;)
boost::array<char, 1> recv_buf;
udp::endpoint remote_endpoint;
boost::system::error_code error;
socket.receive_from(boost::asio::buffer(recv_buf),
remote_endpoint, 0, error);
if (error && error != boost::asio::error::message_size)
throw boost::system::system_error(error);
接着实现向客户端发送数据.
std::string message = make_daytime_string();
向remote_endpoint发送响应.
boost::system::error_code ignored_error;
socket.send_to(boost::asio::buffer(message),
remote_endpoint, 0, ignored_error);
最后处理异常.
catch (std::exception& e)
std::cerr << e.what() << std::endl;
return 0;
Daytime6- daytime异步UDP服务端
main()函数
int main()
创建服务对象接收客户端请求,并运行io_service对象.
boost::asio::io_service io_service;
udp_server server(io_service);
io_service.run();
catch (std::exception& e)
std::cerr << e.what() << std::endl;
return 0;
udp_server类
class udp_server
public:
构造函数初始化socket并侦听UDP的13端口.
udp_server(boost::asio::io_service& io_service)
: socket_(io_service, udp::endpoint(udp::v4(), 13))
start_receive();
private:
void start_receive()
ip::udp::socket::async_receive_from()
函数使应用程序在后台侦听新的请求.当接收到请求,io_service对象使用两个参数来调用handle_receive函数:一个描述操作成功失败的boost::system::error_code类型参数,和一个size_t类型的bytes_transferred 指定接收到的字节数.
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
handle_receive()函数处理客户端请求.
void handle_receive(const boost::system::error_code& error,
std::size_t /*bytes_transferred*/)
error参数包含异步操作的结果.由于这里只提供了一个字节的recv_buffer_来存放客户端请求,如果客户端发送的数据过长则io_service会返回错误信息.如果发生错误则忽略.
if (!error || error == boost::asio::error::message_size)
生成发送给客户端的数据.
boost::shared_ptr<std::string> message(
new std::string(make_daytime_string()));
调用
ip::udp::socket::async_send_to()
函数将数据发送到客户端.
socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
boost::bind(&udp_server::handle_send, this, message,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
当初始化异步操作时,如果使用boost::bind(),必须指定与回调函数相匹配的参数列表.本程序中,两个参数占位符(boost::asio::placeholders::error 和 boost::asio::placeholders::bytes_transferred)应该被移除.
开始侦听下一个客户端请求.
start_receive();
对客户请求的更多处理由handle_send()负责.
handle_send()函数在服务请求结束后调用.
void handle_send(boost::shared_ptr<std::string> /*message*/,
const boost::system::error_code& /*error*/,
std::size_t /*bytes_transferred*/)
udp::socket socket_;
udp::endpoint remote_endpoint_;
boost::array<char, 1> recv_buffer_;
Daytime7-TCP/UDP异步服务
本范例程序展示如何将已经写过的两个异步服务整合到一个服务程序中.
main()函数
int main()
boost::asio::io_service io_service;
创建一个接收TCP客户端连接的服务对象.
tcp_server server1(io_service);
创建一个接收UDP客户端请求的服务对象.
udp_server server2(io_service);
已经创建了两个基于io_service对象上的工作对象.
io_service.run();
catch (std::exception& e)
std::cerr << e.what() << std::endl;
return 0;
tcp_connection 和 tcp_server 类
如下两个类取自Daytime3范例.
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
return pointer(new tcp_connection(io_service));
tcp::socket& socket()
return socket_;
void start()
message_ = make_daytime_string();
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this()));
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
void handle_write()
tcp::socket socket_;
std::string message_;
class tcp_server
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
start_accept();
private:
void start_accept()
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
if (!error)
new_connection->start();
start_accept();
tcp::acceptor acceptor_;
udp_server 类
同样,下面的类取自上一个范例.
class udp_server
public:
udp_server(boost::asio::io_service& io_service)
: socket_(io_service, udp::endpoint(udp::v4(), 13))
start_receive();
private:
void start_receive()
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error));
void handle_receive(const boost::system::error_code& error)
if (!error || error == boost::asio::error::message_size)
boost::shared_ptr<std::string> message(
new std::string(make_daytime_string()));
socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
boost::bind(&udp_server::handle_send, this, message));
start_receive();
void handle_send(boost::shared_ptr<std::string> /*message*/)
udp::socket socket_;
udp::endpoint remote_endpoint_;
boost::array<char, 1> recv_buffer_;
本范例展示如何为异步操作分配必需的内存.
boost_asio/example/allocation/server.cpp
本范例展示如何为Socket读写操作创建有引用计数的缓冲区.
boost_asio/example/buffers/reference_counted.cpp
本范例实现了聊天程序的服务端和客户端.这个程序使用具有6字节的消息头和可变长消息体的自定义协议.
boost_asio/example/chat/chat_message.hpp
boost_asio/example/chat/chat_client.cpp
boost_asio/example/chat/chat_server.cpp
下面针对POSIX的聊天客户端演示如何使用
posix::stream_descriptor
类执行控制台输入输出.
boost_asio/example/chat/posix_chat_client.cpp
展示如何使用同步和异步操作实现一系列简单的客户端和服务端.
boost_asio/example/echo/async_tcp_echo_server.cpp
boost_asio/example/echo/async_udp_echo_server.cpp
boost_asio/example/echo/blocking_tcp_echo_client.cpp
boost_asio/example/echo/blocking_tcp_echo_server.cpp
boost_asio/example/echo/blocking_udp_echo_client.cpp
boost_asio/example/echo/blocking_udp_echo_server.cpp
针对POSIX 的范例程序演示了如何使用Boost.Asio结合fork()系统调用.第一个范例阐述了如何启动守护进程:
boost_asio/example/fork/daemon.cpp
第二个范例阐述了如何在完成句柄中启动进程.
boost_asio/example/fork/process_per_connection.cpp
HTTP客户端
范例程序简单的实现了HTTP1.0客户端.程序演示了如何使用read_until和async_read_until函数.
boost_asio/example/http/client/sync_client.cpp
boost_asio/example/http/client/async_client.cpp
HTTP服务
范例阐述了在单线程中使用asio实现HTTP1.0服务.演示了如何执行清除命令结束未完成的异步操作.
boost_asio/example/http/server/connection.cpp
boost_asio/example/http/server/connection.hpp
boost_asio/example/http/server/connection_manager.cpp
boost_asio/example/http/server/connection_manager.hpp
boost_asio/example/http/server/header.hpp
boost_asio/example/http/server/main.cpp
boost_asio/example/http/server/mime_types.cpp
boost_asio/example/http/server/mime_types.hpp
boost_asio/example/http/server/reply.cpp
boost_asio/example/http/server/reply.hpp
boost_asio/example/http/server/request.hpp
boost_asio/example/http/server/request_handler.cpp
boost_asio/example/http/server/request_handler.hpp
boost_asio/example/http/server/request_parser.cpp
boost_asio/example/http/server/request_parser.hpp
boost_asio/example/http/server/server.cpp
boost_asio/example/http/server/server.hpp
HTTP服务2
使用io_service-per-CPU 设计的HTTP服务.
boost_asio/example/http/server2/connection.cpp
boost_asio/example/http/server2/connection.hpp
boost_asio/example/http/server2/header.hpp
boost_asio/example/http/server2/io_service_pool.cpp
boost_asio/example/http/server2/io_service_pool.hpp
boost_asio/example/http/server2/main.cpp
boost_asio/example/http/server2/mime_types.cpp
boost_asio/example/http/server2/mime_types.hpp
boost_asio/example/http/server2/reply.cpp
boost_asio/example/http/server2/reply.hpp
boost_asio/example/http/server2/request.hpp
boost_asio/example/http/server2/request_handler.cpp
boost_asio/example/http/server2/request_handler.hpp
boost_asio/example/http/server2/request_parser.cpp
boost_asio/example/http/server2/request_parser.hpp
boost_asio/example/http/server2/server.cpp
boost_asio/example/http/server2/server.hpp
HTTP服务3
使用单个io_service并在线程池上调用io_service::run()的HTTP服务.
boost_asio/example/http/server3/connection.cpp
boost_asio/example/http/server3/connection.hpp
boost_asio/example/http/server3/header.hpp
boost_asio/example/http/server3/main.cpp
boost_asio/example/http/server3/mime_types.cpp
boost_asio/example/http/server3/mime_types.hpp
boost_asio/example/http/server3/reply.cpp
boost_asio/example/http/server3/reply.hpp
boost_asio/example/http/server3/request.hpp
boost_asio/example/http/server3/request_handler.cpp
boost_asio/example/http/server3/request_handler.hpp
boost_asio/example/http/server3/request_parser.cpp
boost_asio/example/http/server3/request_parser.hpp
boost_asio/example/http/server3/server.cpp
boost_asio/example/http/server3/server.hpp
HTTP服务4
使用无栈协同技术实现单线程HTTP服务.
boost_asio/example/http/server4/coroutine.hpp
boost_asio/example/http/server4/file_handler.cpp
boost_asio/example/http/server4/file_handler.hpp
boost_asio/example/http/server4/header.hpp
boost_asio/example/http/server4/main.cpp
boost_asio/example/http/server4/mime_types.cpp
boost_asio/example/http/server4/mime_types.hpp
boost_asio/example/http/server4/reply.cpp
boost_asio/example/http/server4/reply.hpp
boost_asio/example/http/server4/request.hpp
boost_asio/example/http/server4/request_parser.cpp
boost_asio/example/http/server4/request_parser.hpp
boost_asio/example/http/server4/server.cpp
boost_asio/example/http/server4/server.hpp
boost_asio/example/http/server4/unyield.hpp
boost_asio/example/http/server4/yield.hpp
展示如何在ICMP上使用原生的Socket ping远程主机.
boost_asio/example/icmp/ping.cpp
boost_asio/example/icmp/ipv4_header.hpp
boost_asio/example/icmp/icmp_header.hpp
展示如何自定义处理函数调用.将完成句柄加入到一个优先级队列而不是直接调用.
boost_asio/example/invocation/prioritised_handlers.cpp
iostream
boost_asio/example/iostreams/daytime_client.cpp
boost_asio/example/iostreams/daytime_server.cpp
boost_asio/example/iostreams/http_client.cpp
展示使用广播向订阅组传输包.
boost_asio/example/multicast/receiver.cpp
boost_asio/example/multicast/sender.cpp
展示如何在asio中使用Boost.Serialization序列号和反序列化结构体,从而实现在Socket上传输数据对象.
boost_asio/example/serialization/client.cpp
boost_asio/example/serialization/connection.hpp
boost_asio/example/serialization/server.cpp
boost_asio/example/serialization/stock.hpp
展示如何向asio的io_service整合自定义功能(本例中是添加了日志功能),以及在
basic_stream_socket<>
上使用自定义服务.
boost_asio/example/services/basic_logger.hpp
boost_asio/example/services/daytime_client.cpp
boost_asio/example/services/logger.hpp
boost_asio/example/services/logger_service.cpp
boost_asio/example/services/logger_service.hpp
boost_asio/example/services/stream_socket_service.hpp
SOCKS4协议
范例客户端程序实现了通过代理通信的SOCKS4协议.
boost_asio/example/socks4/sync_client.cpp
boost_asio/example/socks4/socks4.hpp
客户端和服务端范例程序演示了在异步操作中使用
ssl::stream<>
模板.
boost_asio/example/ssl/client.cpp
boost_asio/example/ssl/server.cpp
下面的一系列范例展示了如何在指定时间之后取消长时间运行的异步操作.
boost_asio/example/timeouts/async_tcp_client.cpp
boost_asio/example/timeouts/blocking_tcp_client.cpp
boost_asio/example/timeouts/blocking_udp_client.cpp
boost_asio/example/timeouts/server.cpp
范例演示了如何定制deadline_time实现不同类型的计时器.
boost_asio/example/timers/tick_count_timer.cpp
boost_asio/example/timers/time_t_timer.cpp
Porthopper
本例演示了混合同步和异步操作,及如何在Boost.Asio中使用Boost.Lambda.
boost_asio/example/porthopper/protocol.hpp
boost_asio/example/porthopper/client.cpp
boost_asio/example/porthopper/server.cpp
展示如何整合实现IO操作的第三方库来实现Reactor风格的操作.
boost_asio/example/nonblocking/third_party_lib.cpp
UNIX领域的Socket
展示如何使用UNIX领域的Socket.
boost_asio/example/local/connect_pair.cpp
boost_asio/example/local/stream_server.cpp
boost_asio/example/local/stream_client.cpp
Windows
展示如何在Boost.Asio中使用Windows特有的TransmitFile函数.
boost_asio/example/windows/transmit_file.cpp
骑白马的包子 · Gene Regulation and Targeted Therapy in Gastric Cancer Peritoneal Metastasis: Radiological Findings 11 月前 |
含蓄的番茄 · 搬运工盒子? - 知乎 1 年前 |
爱笑的汉堡包 · 东台创新� - 搜狗图片搜索 1 年前 |