Boost.Asio,libevent和ACE之间关于Socket编程的比较(★firecat推荐★)

文章来源:http://blog.163.com/miky_sun/blog/static/3369405201041753652505/

ACE官网 http://download.dre.vanderbilt.edu/

boost官网 http://www.boost.org/

boost sourceforge http://sourceforge.net/projects/boost/files/

boost第三方教程

http://theboostcpplibraries.com/

http://zh.highscore.de/cpp/boost/

libevent官网http://libevent.org/

https://github.com/libevent/libevent

http://sourceforge.net/projects/levent/

Asio官网 http://think-async.com/

Asio Linux性能 http://think-async.com/Asio/LinuxPerformanceImprovements

Asio sourceforge http://sourceforge.net/projects/asio/files/

Asio samples https://github.com/mabrarov/asio_samples

第三方开源项目高性能网络服务器 http://www.oschina.net/project/tag/352/network-libs

第三方开源项目HP-Socket https://github.com/ldcsaa/HP-Socket

ACE是一个很成熟的中间件产品,为自适应通讯环境,但它过于宏大,一堆的设计模式,架构是一层又一层,对初学者来说,有点困难。 
ASIO是基本Boost开发的异步IO库,封装了Socket,简化基于socket程序的开发。

最近分析ASIO的源代码,让我无不惊呀于它设计。在ACE中开发中的内存管理一直让人头痛,ASIO的出现,让我看到新的曙光,成为我新的好伙伴。简单地与ACE做个比较。

boost::asio是一个高性能的网络开发库,Windows下使用IOCP,Linux下使用epoll。与ACE不同的是,它并没有提供一个网络框架,而是采取组件的方式来提供应用接口。但是对于常见的情况,采用一个好用的框架还是能够简化开发过程,特别是asio的各个异步接口的用法都相当类似。

Boost.Asio是利用当代C++的先进方法,跨平台,异步I/O模型的C++网络库.


ACE网络库在使用中,一直对其中的内存管理搞得一头雾水,分配的内存需要在哪里释放都不知道,ACE不愧是一个做研究用的库, 可以说里面的封装把设计模式这本书中列出的模式都在代码里面实现了一番,用起来感觉是在用java一样,如果你想使用ACE作为你的网络库, 千万不要仅仅把它当成一个网络库使用, 你要把它当成一个框架来使用,如果你只想用它的网络库, 那大可不必用ACE, 因为它太庞大了,学习起来太费劲。但是你把它当成一个框架来用,你会感觉用的还真爽,该有的东西都有,比如线程池,内存池,定时器,递归锁等,都很方便的。Boost的ASIO,在内存管理方面要直观的多。下面简单地与ACE做个比较。

1.层次架构:

ACE底层是C风格的OS适配层,上一层基于C++的wrap类,再上一层是一些框架(Accpetor, Connector,Reactor,Proactor等),最上一层是框架上服务。

Boost.ASIO与之类似,底层是OS的适配层,上一层一些模板类,再上一层模板类的参数化(TCP/UDP),再上一层是服务,它只有一种框架为io_service。

libevent在不同的操作系统下,做了多路复用模型的抽象,可以选择使用不同的模型,通过事件函数提供服务。

2.涉及范围:
ACE包含了日志,IPC,线程池,共享内存,配置服务,递归锁,定时器等。
ASIO只涉及到Socket,提供简单的线程操作。
libevent只提供了简单的网络API的封装, 线程池, 内存池, 递归锁等均需要自己实现。

3.设计模式:
ACE主要应用了Reactor,Proactor等。
而ASIO主要应用了Proactor。
libevent为Reactor模式

4.线程调度:
ACE的Reactor是单线程调度,Proactor支持多线程调度。
ASIO支持单线程与多线程调度。
libevent的线程调度需要自己来注册不同的事件句柄。

5.事件分派处理:
ACE主要是注册handler类,当事件分派时,调用其handler的虚挂勾函数。实现ACE_Handler / ACE_Svc_Handler / ACE_Event_handler等类的虚函数。
ASIO是基于函数对象的hanlder事件分派。任何函数都可能成为hanlder,少了一堆虚表的维护,调度上优于ACE。
libevent基于注册的事件回调函数来实现事件分发。

6.发布方式:
ACE是开源免费的,不依赖于第3方库, 一般应用使用它时,以动态链接的方式发布动态库。
ASIO是开源免费的,依赖Boost,应用使用时只要include头文件,不需动态库。
libevent为开源免费的,一般编译为静态库进行使用。

7.可移植性:
ACE支持多种平台,可移植性不存在问题,据说socket编程在linux下有不少bugs。
ASIO支持多种平台,可移植性不存在问题。
libevent主要支持linux平台,freebsd平台, 其他平台下通过select模型进行支持, 效率不是太高。

8.开发难度:
基于ACE开发应用,对程序员要求比较高,要用好它,必须非常了解其框架。在其框架下开发,往往new出一个对象,不知在什么地方释放好。
基于ASIO开发应用,要求程序员熟悉函数对象,函数指针,熟悉boost库中的boost::bind。内存管理控制方面。
基于libevent开发应用,相对容易, 具体大家可以参考memcached这个开源的应用,里面使用了libevent这个库。

我个人觉得,如果应用socket编程,使用BOOST::ASIO开发比较好,开发效率比较高。ACE适合于理论研究,它本来就是源于Douglas的学术研究。基于BOOST::ASIO开发的网络模型,分为CLIENT/SERVER 两部分,特别适合小公司,公共组件不够强大,需要跨平台时更适合,MAC OS /WIN32/LINUX。支持 TCP/UDP/UDT主要的协议,另外HTTP SSL PROXY等有极好的例子,方便加入的。用户开发起来很简单,无论是CLIENT/SERVER 只需要些5个回调函数, ON_OPEN ON_CLOSE ON_READ ON_WRITE进行具体的业务处理即可。SERVER连接其它SERVER也非常简单。效率么,只能说很高。仅次于大公司在LINUX下或WINDOWS下专门做的组建。。这个原因么。大家可想一想。其中支持UDT协议称为可靠的UDP。传媒体,大文件很不错哦。

推荐教程:

(原创)如何使用boost.asio写一个简单的通信程序(一)

(原创)如何使用boost.asio写一个简单的通信程序(二)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

http服务器使用BOOST::ASIO框架、socket服务器
基于IO完成端口模型实现网络通信,经正规压力测试工具测试并发10万级,缓存使用MEMCACHE

车联网后台服务器
模块:设备网关 设备业务处理 手机网关 手机推送 透传服务器 缓存服务器 日志服务器
运行环境:windows C++语言 SqlServer 2008R2数据库
使用技术:线程池、数据库连接池、线程同步、单列模板、智能指针、IOCP模型、BOOST::ASIO框架、STL、
数据库存储过程、函数、视图编写、c++面向对象、封装、继承、多态特性、数据加密、第三方接口调用、TCP/IP通信
实现功能:(HTTP服务器)手机终端数据请求响应,车技终端数据请求响应 HTTP POST请求
(SOCKET服务器) OBD设备GPS、OBD、行程、驾驶行为、故障码数据解析入库、消息推送、数据缓存

IOCP、EPOLL等高并发网络通信模型,HTTP服务器、Socket服务器搭建
Sql2008/MYSQL/SQLITE等数据库,数据库连接池。存储过程、函数、视图。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

为何 Boost 的 Asio 要使用 Proactor 模式实现?

涉及到事件分享器的两种模式称为:Reactor and Proactor。 Reactor模式是基于同步I/O的,而Proactor模式是和异步I/O相关的。 在Reactor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是socket可读写),事件分离者就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。

而在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。举例来说,在Windows上事件处理者投递了一个异步IO操作(称有overlapped的技术),事件分离者等IOCompletion事件完成[1]。 这种异步模式的典型实现是基于操作系统底层异步API的,所以我们可称之为“系统级别”的或者“真正意义上”的异步,因为具体的读写是由操作系统代劳的。

举另外个例子来更好地理解Reactor与Proactor两种模式的区别。这里我们只关注read操作,因为write操作也是差不多的。下面是Reactor的做法:

  • 某个事件处理者宣称它对某个socket上的读事件很感兴趣;
  • 事件分离者等着这个事件的发生;
  • 当事件发生了,事件分离器被唤醒,这负责通知先前那个事件处理者;
  • 事件处理者收到消息,于是去那个socket上读数据了。 如果需要,它再次宣称对这个socket上的读事件感兴趣,一直重复上面的步骤;

下面再来看看真正意义的异步模式Proactor是如何做的:

  • 事件处理者直接投递发一个写操作(当然,操作系统必须支持这个异步操作)。 这个时候,事件处理者根本不关心读事件,它只管发这么个请求,它魂牵梦萦的是这个写操作的完成事件。这个处理者很拽,发个命令就不管具体的事情了,只等着别人(系统)帮他搞定的时候给他回个话。
  • 事件分离者等着这个读事件的完成(比较下与Reactor的不同);
  • 当事件分离者默默等待完成事情到来的同时,操作系统已经在一边开始干活了,它从目标读取数据,放入用户提供的缓存区中,最后通知事件分离者,这个事情我搞完了;
  • 事件分享者通知之前的事件处理者: 你吩咐的事情搞定了;
  • 事件处理者这时会发现想要读的数据已经乖乖地放在他提供的缓存区中,想怎么处理都行了。如果有需要,事件处理者还像之前一样发起另外一个写操作,和上面的几个步骤一样。

现行做法

开源C++开发框架 ACE(Douglas Schmidt, et al.开发) 提供了大量平台独立的底层并发支持类(线程、互斥量等)。 同时在更高一层它也提供了独立的几组C++类,用于实现Reactor及Proactor模式。 尽管它们都是平台独立的单元,但他们都提供了不同的接口。

ACE Proactor在MS-Windows上无论是性能还在健壮性都更胜一筹,这主要是由于Windows提供了一系列高效的底层异步API。

(这段可能过时了点吧) 不幸的是,并不是所有操作系统都为底层异步提供健壮的支持。举例来说, 许多Unix系统就有麻烦。因此, ACE Reactor可能是Unix系统上更合适的解决方案。 正因为系统底层的支持力度不一,为了在各系统上有更好的性能,开发者不得不维护独立的好几份代码: 为Windows准备的ACE Proactor以及为Unix系列提供的ACE Reactor。

就像我们提到过的,真正的异步模式需要操作系统级别的支持。由于事件处理者及操作系统交互的差异,为Reactor和Proactor设计一种通用统一的外部接口是非常困难的。这也是设计通行开发框架的难点所在。

Linux下高性能的网络库中大多使用的Reactor 模式去实现,Boost Asio在Linux下用epoll和select去模拟proactor模式,影响了它的效率和实现复杂度,
看陈硕的自己的Linux下Reactor网络库和ASIO的性能对比,大概比asio性能(吞吐量)高1/5.既然Linux下网络库用Reactor性能才高,为什么Boost ASIO Linux下要用模拟的Proactor模式?或者说为什么ASIO不在win和linux都用Reactor模式?这样的选择是不是可以性能更好?和更加适应市场?服务器端毕竟大量都是Linux.
Windows 下很难实现高效可伸缩的 Reactor。首先,Win32 API 里 WaitForMultipleObjects 只能同时等待 64 个 handle (MAXIMUM_WAIT_OBJECTS);其次 WinSock 的 select() 实现又很 buggy,特别是在错误处理方面有很多奇葩行为(具体见各种跨平台网络库代码中对此的注释);最后,Windows Vista 新增的 WSAPoll() 函数与 POSIX 的 poll() 又不尽兼容( daniel.haxx.se/blog/201 )。
Windows 有自己的一套高效异步IO模型(几乎等同于Proactor),同时支持文件IO和网络IO;但 Linux 只有高效的网络同步IO(epoll 之类的 io multiplexing 是同步的Reactor,且不支持磁盘文件),二者的高效IO编程模型从根本上不兼容(Windows 可以把网络事件发到 GUI 线程的事件队列中,有点类似 Reactor,但是似乎一个进程只能有一个 GUI 线程,因此在多核系统上其伸缩性受限)。
因此,ASIO 要想高效且跨平台,只能用 Proactor 模型了。不可避免地会在 Linux 上损失一点儿效率。

展开阅读全文

没有更多推荐了,返回首页