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

异常处理VS错误代码

Boost.Asio允许同时使用异常处理或者错误代码,所有的异步函数都有抛出错误和返回错误码两种方式的重载。当函数抛出错误时,它经常抛出boost::system::system_error的错误。

using boost::asio;

ip::tcp::endpoint ep;

ip::tcp::socket sock(service);

sock.connect(ep); // Line 1

boost::system::error_code err;

sock.connect(ep, err); // Line 2

在前面的代码中,sock.connect(ep)会抛出错误,sock.connect(ep, err)则会返回一个错误码。

看一下下面的代码片段:

try {

sock.connect(ep);

} catch(boost::system::system_error e) {

std::cout << e.code() << std::endl;

}

下面的代码片段和前面的是一样的:

boost::system::error_code err;

sock.connect(ep, err);

if ( err)

std::cout << err << std::endl;

当使用异步函数时,你可以在你的回调里面检查其返回的错误码。异步函数从来不抛出异常,因为这样做毫无意义。那谁会捕获到它呢?

在你的异步函数中,你可以使用异常处理或者错误码(随心所欲),但要保持一致性。同时使用这两种方式会导致问题,大部分时候是崩溃(当你不小心出错,忘记去处理一个抛出来的异常时)。如果你的代码很复杂(调用很多socket读写函数),你最好选择异常处理的方式,把你的读写包含在一个函数try {} catch块里面。

void client_session(socket_ptr sock) {

try {

...

} catch ( boost::system::system_error e) {

// handle the error

}

}

如果使用错误码,你可以使用如下的代码片段很好地看到连接是何时关闭的:

char data[512];

boost::system::error_code error;

size_t length = sock.read_some(buffer(data), error);

if (error == error::eof)

return; // Connection closed

Boost.Asio的所有错误码都包含在boost::asio::error的命名空间中(以便你创造一个大型的switch来检查错误的原因)。如果想要了解更多的细节,请参照boost/asio/error.hpp头文件。

Boost.Asio中的线程

当说到Boost.Asio的线程时,我们经常讨论:

io_service:io_service是线程安全的。几个线程可以同时调用io_service::run()。大多数情况下你可能在一个必须等待所有异步操作完成之后才能继续执行的单线程函数中调用io_service::run()。然而,你其实可以在多个线程中调用io_service::run()。这会阻塞所有调用io_service::run()的线程。只要线程中的任何一个调用了io_service::run(),所有的回调都会同时被调用;这也就意味着,当你在一个线程中调用io_service::run()时,所有的回调都被调用了。

socket:socket类不是线程安全的。所以,你要避免在某个线程里读一个socket时,同时在另外一个线程里面对其进行写入操作。(通常来说这种操作都是不推荐的,更别说Boost.Asio)。

utility:就utility来说,因为它不是线程安全的,所以通常也不提倡在多个线程里面同时使用。里面的方法经常只是在很短的时间里面使用一下,然后就释放了。

除了你自身的线程,Boost.Asio本身也包含几个线程。但是能保证那些线程不会调用你的代码。这也意味着,只有调用了io_service::run()方法的线程才会调用回调函数。

不仅仅是网络通信

除了网络通信,Boost.Asio还包含了其他的I/O功能。

Boost.Asio支持信号量,比如SIGTERM(软件终止)、SIGINT(中断信号)、SIGSEGV(段错误)等等。

你可以创建一个signal_set实例,指定异步等待的信号量,然后当这些信号量产生时,就会调用你的异步处理程序:

void signal_handler(const boost::system::error_code & err, int signal)

{

// log this, and terminate application

}

boost::asio::signal_set sig(service, SIGINT, SIGTERM);

sig.async_wait(signal_handler);

如果SIGINT产生,你就能在你的signal_handler回调中捕获到它。

你可以使用Boost.Asio轻松地连接到一个串行端口。在Windows上端口名称是COM7,在POSIX平台上是/dev/ttyS0。

io_service service;

serial_port sp(service, "COM7");

打开端口后,你就可以使用下面的代码设置一些端口选项,比如端口的波特率、奇偶校验和停止位。

serial_port::baud_rate rate(9600);

sp.set_option(rate);

打开端口后,你可以把这个串行端口看做一个流,然后基于这点,使用自由函数对串行端口进行读/写操作。比如async_read(), write, async_write(), 就像下面的代码片段:

char data[512];

read(sp, buffer(data, 512));

Boost.Asio也可以连接到Windows的文件,然后同样使用自由函数,比如read(), asyn_read()等等,像下面的代码片段:

HANDLE h = ::OpenFile(...);

windows::stream_handle sh(service, h);

char data[512];

read(h, buffer(data, 512));

对于POXIS文件描述符,比如管道,标准I/O和各种设备(但不包括普通文件)你也可以这样做,就像下面的代码所做的一样:

posix::stream_descriptor sd_in(service, ::dup(STDIN_FILENO));

char data[512];

read(sd_in, buffer(data, 512));

计时器

一些I/O操作需要一个完成截止时间。你只能在异步操作上进行应用(同步意味着阻塞,因此没有截止时间)。例如,你的下一条信息必须在100毫秒内从你的同伴传递给你。

bool read = false;

void deadline_handler(const boost::system::error_code &) {

std::cout << (read ? "read successfully" : "read failed") <<

std::endl;

}

void read_handler(const boost::system::error_code &) {

read = true;

}

ip::tcp::socket sock(service);

read = false;

char data[512];

sock.async_read_some(buffer(data, 512));

deadline_timer t(service, boost::posix_time::milliseconds(100));

t.async_wait(&deadline_handler);

service.run();

在上一个代码片段中,如果你在截止时间之前读完了数据,read则被设置成true,如此我们的伙伴就及时地通知了我们。否则,当deadline_handler被调用时,read还是false,也就意味着我们没有满足我们的截止时间。

Boost.Asio也支持同步计时器,当时他们通常和一个简单的sleep操作是一样的。boost::this_thread::sleep(500);这段代码和下面的代码片段完成了同一件事情:

deadline_timer t(service, boost::posix_time::milliseconds(500));

t.wait();

时间: 2024-11-04 17:46:27

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

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

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

同步VS异步 首先,异步编程和同步编程是有极大的不同的.在同步编程中,你所有的操作都是顺序执行的,比如从一个socket中读取(请求),然后写入(回应)到socket中.每一个操作操作都是阻塞的.因为操作是阻塞的,所以为了不影响主程序,当读写一个socket时,通常创建一个或多个线程来处理socket的输入/输出.因此,同步的服务端/客户端通常是多线程的. 相反的,异步编程是事件驱动的.你启动了一个操作,但是你不知道它何时会结束:你只是提供一个回调,当操作结束时,它会调用这个API,并返回操作结