Boost.Asio c++ 网络编程翻译(29)

Boost.Asio-进阶话题

这一章对Boost.Asio的一些进阶话题进行了阐述。在日常编程中研究这些问题是不太可能的,但是知道这些肯定是有好处的:

  • 如果调试失败,你需要看Boost.Asio能帮到你什么
  • 如果你需要处理SSL,看Boost.Asio能帮你多少
  • 如果你指定一个操作系统,看Boost.Asio为你准备了哪些额外的特性

Asio VS Boost.Asio

Boost.Asio的作者也保持了Asio。你可以用Asio的方式来思考,因为它在两种情况中都有:Asio(非Boost的)和Boost.Asio。作者声明过更新都会先在非Boost中出现,然后过段时间后,再加入到Boost的发布中。

不同点被归纳到下面几条:

  • Asio被定义在asio::的命名空间中,而Boost.Asio被定义在boost::asio::中
  • Asio的主头文件是asio.hpp,而Boost.Asio的头文件是boost/asio.hpp
  • Asio也有一个启动线程的类(和boost::thread一样)
  • Asio提供它自己的错误码类(asio::error_code代替boost::system::error_code,然后asio:system_error代替boost::systrem::system_error)

你可以在这里查阅更多Asio的信息:http://think_async.com

你需要自己决定你选择的版本,我选择Boost.Asio。下面是一些当你做选择时需要考虑的问题:

  • Asio的新版本比Boost.Asio的新版本发布要早(因为Boost的版本更新比较少)
  • Asio只有头文件(而Boost.Asio的部分依赖于其他Boost库,这些库可能需要编译)
  • Asio和Boost.Asio都是非常成熟的,所以除非你非常需要一些Asio新发布的特性,Boost.Asio是非常保险的选择,而且你也可以同时拥有其他Boost库的资源

尽管我不推荐这样,你可以在一个应用中同时使用Asio和Boost.Asio。如果情况允许,这自然会发生,比如,如果你使用Asio,然后一些第三方库是Boost.Asio,反之亦然。

调试

调试同步应用往往比调试异步应用要简单。对于同步应用,如果阻塞了,你会跳转进入调试,然后你会知道你在哪(同步意味着有序的)。然后,如果是异步,事件不是有序发生的,所以在调试中是非常难知道到底发生了什么的。

为了避免这种情况,首先,你需要深入了解协程。如果正确实现了,你基本不会碰到一点异步调试的问题。

以防万一,在做异步编码的时候,Boost.Asio拉了你一把;Boost.Asio允许“handler追踪”,当BOOST_ASIO_ENABLE_HANDLER_TRACKING被定义时,Boost.Asio会写很多辅助的输出到标准错误流,纪录时间,异步操作,以及和完成处理handler的关系。

handler追踪信息

信息不是如此容易就能读懂的,但是还是非常有用。Boost.Asio的输出是@asio|<timestamp>|<action>|<description> 。

第一个标签永远都是@asio,因为其他代码也会输出到标准错误流(和std::error相当),所以你可以非常简单的用这个标签过滤从Boost.Asio打印出来的信息。timestamp实例从1970年1月1号到现在的秒数和毫秒数。action实例可以是下面任何一种:

  • >n:这个在我们进入handler n的时候使用。description实力包含了我们发送给handler的参数。
  • <n:这个在我们退出handler n的时候使用。
  • !n:这个当我们因为异常退出handler n的时候使用。
  • -n:这个当handler n在没有调用的情况就退出的时候使用;可能是因为io_service实例被删除地太快了(在n有机会被调用之前)
  • n*m:这个当handler n创建了一个新的有完成处理hanlder m的异步操作时被调用。description实例展示的就是异步操作开始的地方。当你看到>m(开始)和<m(结束)时completion句柄被调用了。
  • n:就像在description中展示的一样,这个当handler n做了一个操作的时候使用(可能是close或者cancel操作)。你一般可以忽略这些信息。
  • 当n是0时,操作是在所有(异步)handler之外被执行的;你经常会在第一个操作时看到这个,或者当你使用信号量的其中一个被触发时。
  • 你需要非常注意类型为!n和-n的信息,这些信息大部分都意味着你的代码有错误。在第一种情形中,异步方法没有抛出异常,所以,异常一定是你自己造成的;你不能让异常跑出你的completion句柄。第二种情形中,你可能太早就销毁了io_service实例,在所有完成处理句被调用之前。

一个例子

为了向你展示一个带帮助信息的例子,我们修改了在第六章 Boost.Asio其他特性 中使用的例子。你所需要做的仅仅是在包含boost/asio.hpp之前添加一个#define

  1. #define BOOST_ASIO_ENABLE_HANDLER_TRACKING
       #include <boost/asio.hpp>
       ...
    

同时,我们也在用户登录和接受到第一个客户端列表时将信息输出到控制台中。输出会如下所示:

@asio|1355603116.602867|0*1|[email protected]_connect
   @asio|1355603116.604867|>1|ec=system:0
   @asio|1355603116.604867|1*2|[email protected]_send
   @asio|1355603116.604867|<1|
   @asio|1355603116.604867|>2|ec=system:0,bytes_transferred=11
   @asio|1355603116.604867|2*3|[email protected]_receive
   @asio|1355603116.604867|<2|
   @asio|1355603116.605867|>3|ec=system:0,bytes_transferred=9
   @asio|1355603116.605867|3*4|[email protected]
   @asio|1355603116.605867|<3|
   @asio|1355603116.605867|>4|
   John logged in
   @asio|1355603116.606867|4*5|[email protected]
   @asio|1355603116.606867|<4|
   @asio|1355603116.606867|>5|
   @asio|1355603116.606867|5*6|[email protected]_send
   @asio|1355603116.606867|<5|
   @asio|1355603116.606867|>6|ec=system:0,bytes_transferred=12
   @asio|1355603116.606867|6*7|[email protected]_receive
   @asio|1355603116.606867|<6|
   @asio|1355603116.606867|>7|ec=system:0,bytes_transferred=14
   @asio|1355603116.606867|7*8|[email protected]
   @asio|1355603116.607867|<7|
   @asio|1355603116.607867|>8|
   John, new client list: John

让我们一行一行分析:

我们进入async_connect,它创建了句柄1(在这个例子中,所有的句柄都是talk_to_svr::step)

  • 句柄1被调用(当成功连接到服务端时)
  • 句柄1调用async_send,这创建了句柄2(这里,我们发送登录信息到服务端)
  • 句柄1退出
  • 句柄2被调用,11个字节被发送出去(login John)
  • 句柄2调用async_receive,这创建了句柄3(我们等待服务端返回登录的结果)
  • 句柄2退出
  • 句柄3被调用,我们收到了9个字节(login ok)
  • 句柄3调用on_answer_from_server(这创建了句柄4)
  • 句柄3退出
  • 句柄4被调用,这会输出John logged in
  • 句柄4调用了另外一个step(句柄5),这写ask_clients
  • 句柄4退出
  • 句柄5进入
  • 句柄5,async_send_ask_clients,创建句柄6
  • 句柄5退出
  • 句柄6调用async_receive,这创建了句柄7(我们等待服务端发送给我们已存在的客户端列表)
  • 句柄6退出
  • 句柄7被调用,我们接受到了客户端列表
  • 句柄7调用on_answer_from_server(这创建了句柄8)
  • 句柄7退出
  • 句柄8进去,然后输出客户端列表(on_clients)

这需要一会去理解,但是一旦你理解了,你就可以分辨出有问题的输出,从而找出需要被修复的那段代码。

时间: 2024-10-19 08:55:02

Boost.Asio c++ 网络编程翻译(29)的相关文章

Boost.Asio c++ 网络编程翻译(1)

第一次翻译,希望大家多多指正 实战出精华 Boost.Asio C++ 网络编程 用具体的C++网络编程例子来提升你的技能 John Torjan 用具体的C++网络编程例子来提升你的技能 Copyright ? 2013 Packt Publishing 版权所有,除了在鉴定文章或者评论中进行简单引用,如果没有经过出版者事先的书面授权,该书的任何部分都不能被转载.存储在检索系统中.或者以任何形式和方式传阅. 在这本书准备发行之前,我们已经尽我们最大的努力去保证书中信息的准确性.但是,这本书中包

Boost.Asio c++ 网络编程翻译(20)

异步服务端 这个图表是相当复杂的:从Boost.Asio出来你可以看到4个箭头指向on_accept,on_read,on_write和on_check_ping.着也就意味着你永远不知道哪个异步调用是下一个完成的调用,但是你可以确定的是它是这4个操作中的一个. 现在,我们是异步的了:我们可以继续保持单线程.接受客户端连接是最简单的部分,如下所示: ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001)

Boost.Asio c++ 网络编程翻译(30)[完结]

PS:至此终于完成了Boost.Asio C++ network programming一书的翻译,这是我人生第一本完整翻译的书,从开始的磕磕绊绊,到最后小有心得,我收获很多.我将把这个系列的博客进行整理和校对,希望有兴趣的人可以帮我一起,来给大家提供更好更专业的阅读体验. 句柄追踪信息到文件 默认情况下,句柄的追踪信息被输出到标准错误流(相当于std::cerr).你想把输出重定向到其他地方的可能性是非常高的.对于控制台应用,输出和错误输出都被默认输出到相同的地方,也就是控制台.但是对于一个w

Boost.Asio c++ 网络编程翻译(14)

保持活动 假如,你需要做下面的操作: io_service service; ip::tcp::socket sock(service); char buff[512]; ... read(sock, buffer(buff)); 在这个例子中,sock和buff的存在时间都必须比read()调用的时间要长.也就是说,在调用read()返回之前,它们都必须有效.这就是你期望的:你传给一个方法的所有参数在参数内部都必须有效.当我们采用异步方式时,事情会变得越复杂. io_service servi

Boost.Asio c++ 网络编程翻译(3)

Boost.Asio入门 什么是Boost.Asio 简单来说,Boost.Asio是一个跨平台的.主要用于网络和其他一些底层输入/输出编程的C++库. 计算机网络的设计方式有很多种,但是Boost.Asio的的方式远远优于它们.它在2005年就被包含进Boost,然后被广大Bosot的用户测试并在很多项目中使用,比如Remobo(http://www.remobo.com),可以让你创建你自己的即时私有网络(IPN),libtorrent(http://www.rasterbar.com/pr

Boost.Asio c++ 网络编程翻译(11)

*_at方法 这些方法在一个流上面做随机存取操作.你来指定read和write操作从什么地方開始(offset): async_read_at(stream, offset, buffer [, completion], handler):这种方法在一个指定的流上从offset处開始运行一个异步的read操作,当操作结束时,他会调用handler. handler的格式为:void handler(const boost::system::error_code&  err, size_t byt

Boost.Asio c++ 网络编程翻译(26)

Boost.Asio-其他特性 这章我们讲了解一些Boost.Asio不那么为人所知的特性.标准的stream和streambuf对象有时候会更难用一些,但正如你所见.它们也有它们的益处.最后,你会看到姗姗来迟的Boost.Asio协程的入口,它能够让你的异步代码变的很易读.这是很惊人的一个特性. 标准stream和标准I/O buffer 读这一章节之前你须要对STL stream和STL streambuf对象有所了解. Boost.Asio在处理I/O操作时支持两种类型的buffer: b

Boost.Asio c++ 网络编程翻译(6)

io_service类 你应该已经发现大部分使用Boost.Asio编写的代码都会使用几个ios_service的实例.ios_service是这个库里面最重要的类:它负责和操作系统打交道,等待所有异步操作的结束,然后为每一个异步操作调用完成处理程序. 如果你选择用同步的方式来创建你的应用,你不需要考虑我将在这一节向你展示的东西. 你可以用几种不同的方式来使用io_service.在下面的例子中,我们有3个异步操作,2个socket连接和一个计时器等待: 有一个io_service和一个处理线程

Boost.Asio c++ 网络编程翻译(7)

Boost.Asio基本原理 这一章涵盖了你使用Boost.Asio时必须知道的一些事情.我们也将深入研究比同步编程更机警.更有乐趣的异步编程. 网络API 这一部分包含了当使用Boost.Asio编写网络应用程序时你必须知道的事情. Boost.Asio命名空间 Boost.Asio的一切都需要包含在boost::asio的命名空间或者其子命名空间内. boost::asio:这是核心类和函数所在的地方.重要的类有io_service和streambuf.类似read, read_at, re