基于事件驱动的高性能开源网络库libevent介绍及安装

基于事件驱动的高性能开源网络库libevent介绍及安装,第1张

libevent是一个轻量级的基于事件驱动的高性能的开源网络库,并且支持多个平台,对多个平台的I/O复用技术进行了封装,当我们编译库的代码时,编译的脚本将会根据OS支持的处理事件机制,来编译相应的代码,从而在libevent接口上保持一致。

在当前的服务器上,面对的主要问题就是要能处理大量的连接。而通过libevent这个网络库,我们就可以调用它的API来很好的解决上面的问题。首先,可以来回顾一下,对这个问题的传统解决方法。

问题: 如何处理多个客户端连接

解决方案1: I/O复用技术

这几种方式都是同步I/O,即当读写事件就绪,他们自己需要负责进行读写,这个读写过程是阻塞的,而异步I/O则不需要自己负责读写,只需要通知负责读写的程序就可以了。

解决方案2: 多线程技术或多进程技术

多线程技术和多进程技术也可以处理高并发的数据连接,因为在服务器中可以产生大量的进程和线程和处理我们需要监视的连接。但是,这两种方式也是有很大的局限性的,比如多进程模型就不适合大量的短连接,因为进程的产生和关闭需要消耗较大的系统性能,同样,还要进程进程间的通信,在CPU性能不足的情况下不太适合。而多线程技术则不太适合处理长连接,因为当我们建立一个进程时,linux中会消耗8G的栈空间,如果我们的每个连接都杵着不断开,那么大量连接长连接后,导致的结果就是内存的大量消耗。

解决方案3: 常用的上述二者复合使用

上述的两种方法各具有优缺点,因此,我们可以将上述的方法结合起来,这也是目前使用较多的处理高并发的方法。多进程+I/O复用或者多线程+I/O复用。而在具体的实现上,又可以分为很多的方式。比如多线程+I/O复用技术,我们使用使用一个主线程负责监听一个端口和接受的描述符是否有读写事件产生,如果有,则将事件分发给其他的工作进程去完成,这也是进程池的理念。

在说完上述的高并发的处理方法之后,我们可以来介绍一个libevent的主要特色了。

同样,lievent也是采用的上述系统提供的select,poll和epoll方法来进行I/O复用,但是针对于多个系统平台上的不同的I/O复用实现方式,libevent进行了重新的封装,并提供了统一的API接口。libevent在实现上使用了事件驱动这种机制,其本质上是一种Reactor模式。

在Libevent中也是一样,向Libevent框架注册相应的事件和回调函数;当这些事件发生时,Libevent会调用这些回调函数处理相应的事件。

lbevent的事件支持三种,分别是网络IO、定时器和信号。定时器的数据结构使用最小堆(Min Heap),以提高效率。网络IO和信号的数据结构采用了双向链表(TAILQ)。

更多linux内核视频教程文本资料免费获取后台私信【内核】。

libevent的安装很简单,我是直接从github上clone下一个源码,然后进行编译安装的。

具体的命令是(假设你已经安装了git):

现在的libevent版本已经到达libevent2了,其增加了多线程的支持,API函数也发生了一些微小的变化。

如果你想知道更多的API使用情况,请点击这里。

下面,就基于libevent2编写一个聊天室服务器。

设计思想: 首先创建一个套接字,进而创建一个事件对此端口进行监听,将所请求的用户组成一个队列,并监听所有的用户事件,当某个用户说话了,产生了读事件,就将该用户的发言发送给队列中的其他用户。

程序分析

需要包含的libevent函数头:

创建一个client结构体,接受连接后存放数据:

先来看下mian函数的处理:

首先,函数初始化了一个用户队列tailq,接着创建了一个socket套接字,并将套接字设定为非阻塞模式,接着对一个全局的evbase事件集合,注册了事件,事件源是listen_fd,回调函数是on_accept,事件发生的情况是EV_READ,而且标志EV_PESIST表明该事件一直存在,而后开启事件扫描循环event_base_dispatch(evbase)。

再看一下回调函数on_accpet实现:

这个回调函数的作用很显然,就是接受了一个客户端的请求,并申请好了一个client信息,将需要的内容填写好,在填写中需要注意的是,又向上述的事件集evbase中注册了一个bufferevent事件client->buf_ev,并注册了回调函数buffered_on_read,buffered_on_error,这三个函数分别是当接受后的连接发生了读或者错误事件后的执行函数。接着,将用户的client结构放入了用户的队列tailq中去。

用户的buffer可读后的执行函数:

执行函数的作用很明显,将libevent管理中的buffer数据读取出,存入本地的data数组内,然后对队列中的client进行检索,如果不是发数据的client,则将数据写入该client的buffer中,发送给该用户。这里注意的是需要反复读取buffer中的数据,防止一个读取并没有读取干净,直到读取不到数据为止。

buffer出错处理函数和上述函数差不多,功能就是出错后,结束掉保存的client结构,详细就不说了。

编译的时候记得修改Makefile中Libevent文件夹的位置

设计思想: 所谓回显服务器就是将客户端发过来的数据再发回去,这里主要也就是说明libevent的纯IO复用实现。实现方法和上面的差不多,甚至可以说更加简单。

程序和上面的聊天服务器差不多,只是在buffer可读的事件函数中,不是将用户的数据发送给其他用户,而是直接发送给用户本身。

设计思想: 上面的方法单纯使用libevent的简单函数来实现服务,但是这里,我们假设我们需要处理的客户端很少,于是我们可以使用对于每个连接我们分配一个线程这样的方式来实现对用户的服务。这种方式简单有效,一对一服务,就算业务逻辑出现阻塞也不怕。

程序分析

首先定义了一些数据结构,worker数据结构定义的是一个工作者,它包含有一个工作线程,和结束标志,需要获取的工作队列,和建立链表需要的指针。job数据结构定义的是 *** 作一个job的方法和对象,这回到程序中,实际上就是指的是事件发生后,封装好的client结构体和处理这个结构体的方法。workqueue数据结构指的是当前的工作队列中的工作者,以及工作队列中的待完成的工作,以及互斥锁和条件变量(因为多个工作进程需要访问这些资源)。

具体的流程就是,用一个主线程监听一个套接字,并将套接字接受到的连接accept,并创建一个client数据结构保存该连接的信息,在这个client结构中注册一个bufferevent事件,注册到client->evbase上(这时候这是向client中的evbase注册了一个事件还没有进行循环这个事件集)。

接着,当监听到某个client有bufferevent事件发生,主线程就把该client结构体和需要进行的工作方法包装成一个job结构,然后把这个job扔到workqueue上去,并通知各个工作者。而后,各个工作者开着的线程就被激活了,疯狂地去workqueue上去抢工作做,某个worker拿到工作后,就可以解包job,根据job的工作说明书(job_function) *** 作工作对象(client)了。这里,job的工作说明有是循环client中的client->evbase,于是这样线程就会一直去监视这个连接的状态,如果有数据就这会调用回调函数进行处理。同时,这个线程也就是阻塞在这里,这对这一个连接负责。

建立workqueue需要的结构体和函数有:

主线程的on_accept函数为:

job中的工作指南为:

设计思想: 假设我们的用户很多,高并发,长连接,那么我们还是来用I/O复用和线程池实现吧,用一个控制线程通过I/O复用负责监听和分发事件,用一组线程池来进行处理事件,这样就可以灵活地将控制逻辑和业务逻辑分开了,见下述讲解。

程序分析

具体的流程和上面的差不多,用一个主线程监听一个套接字,并将套接字接受到的连接accept,并创建一个client数据结构保存该连接的信息,在这个client结构中注册一个bufferevent事件,但是这里,将事件注册到accept_evbase中,仍然用主线程进行监听。

而面对监听后出现的事件,将client和 *** 作client的方法打包成一个job,放到上述的workqueue中去,让工作进程来完成。这样的 *** 作和上述的差别在于上述方法将bufferevent注册到client中的evbase中,用工作线程监听,而本方法用主线程监听,工作线程负责处理监听产生的事件。

这要的差别在于两个函数 on_accept函数:

在buffered_on_read中,提交job。

在job工作指南server_job_function中就可以做你工作该做的事儿了,根据发来的信息进行数据库处理,http返回等等。

双引擎ev模式不可用怎么办亲,你好!这个情况是动力电池电量过低,导致的纯电模式无法行驶,可以用混动模式跑一会,电池达到一半以上电量,就可以使用纯电模式了。EV功能受限是指车辆的高压电部分全部不能正常工作,当然了,这并不意味着整个高压系统都坏了,而是其中某个部件有问题,激活了这套系统的高压互锁程序。有点像我们以前的大众车那样,只要坏了其中一个小东西整辆车就启动不

ev6怎么在主机上编程不是超频的方法之一,也不是用来超频的。

我们知道,电脑有许多配件,配件不同,速度也就不同。在286、386和早期的486电脑里,CPU的速度不是太高,和内存保持一样的速度。后来随着 CPU 速度的飞速提升,内存由于电气结构关系,无法象CPU那样提升很高的速度(就算现在内存达到400、533,但跟CPU的几个G的速度相比,根本就不是一个级别的),于是造成了内存和CPU之间出现了速度差异,这时就提出一个CPU的主频、倍频和外频的概念,外频顾名思义就是CPU外部的频率,也就是内存的频率,CPU以这个频率来与内存联系。CPU的主频就是CPU内部的实际运算速度,主频肯定是比外频高的,高一定的倍数,这个数就是倍频。举个例子,你从电脑LJ堆里拣到一个被抛弃的INTEL 486 CPU,上面印着486 DX/2 66。这个486的CPU的主频是66MHZ,DX/2代表是2倍频的,于是算出CPU的外频是33MZ,也就是内存的工作频率,这同时也是前端总线 FSB的频率。因为CPU是通过前端总线来与内存发生联系的,所以内存的工作频率(或者说外频也行)就是前端总线的频率。刚才这个LJ堆里的486 CPU,前端总线的频率就是33MZ。这样的前端总线结构一直延续到486之后的奔腾(俗话说的586)、奔腾2、奔腾3,例如一颗奔3 933MHZ的CPU,外频133,也就是说它的前端总线是133MHZ,内存工作频率也是133。

到了奔腾4年代,内存和CPU的工作模式发生了改变,前端总线的概念也变得有些复杂。奔腾4 CPU采用了Quad Pumped(4倍并发)技术,该技术可以使系统总线在一个时钟周期内传送4次数据,也就是传输效率是原来的4倍,相当于用了4条原来的前端总线来和内存发生联系。在外频仍然是133MHZ的时候,前端总线的速度增加4倍变成了133X4=533MHZ,当外频升到200MHZ,前端总线变成 800MHZ,所以你会看到533前端总线的P4和800前端总线的P4,就是这样来的。他们的实际外频只有133和200,但由于人们保留了以前老的概念——前端总线就是外频,所以习惯了这样的叫法:533外频的P4和800外频的P4。其实还是叫533前端总线或533 FSB的P4比较合适。

那内存的情况怎么样呢?外频不完全等于前端总线了,那外频还等于内存的频率吗?内存发展到了DDR,跟原来相比,一个时钟周期内可以传送比原来多一倍的数据,DDR就是DOUBLE DATA RATE的缩写,意思就是双倍的数据传输速率。在133MHZ的外频下,DDR的传输速度是266,外频提高到200MHZ的时候,DDR的传输速度是 400,DDR266的内存和DDR400的内存就是这个意思。

再看一下现在外频、内存频率、CPU的前端总线的的关系。在以前P3 的时候,133的外频,内存的频率就是133,CPU的前端总线也是133,三者是一回事。现在P4的CPU,在133的外频下,前端总线达到了 533MHZ,内存频率是266(DDR266)。问题出现了,前端总线是CPU与内存发生联系的桥梁,P4这时候的前端总线达到533之高,而内存只有 266的速度,内存比CPU的前端总线慢了一半,理论上CPU有一半时间要等内存传数据过来才能处理数据,等于内存拖了CPU的后腿。这样的情况的确存在的,845和848的主板就是这样。于是提出一个双通道内存的概念,两条内存使用两条通道一起工作,一起提供数据,等于速度又增加一倍,两条DDR266 就有266X2=533的速度,刚好是P4 CPU的前端总线速度,没有拖后腿的问题。外频提升到200的时候,CPU前端总线变为800,两条DDR400内存组成双通道,内存传输速度也是800 了。所以要P4发挥好,一定要用双通道内存,865以上的主板都提供这个功能。但845和848主板就没有内存双通道功能了。

刚才说的是INTEL P4的FSB概念,它的对手AMD的CPU有所不同。

旧的462针脚的AMD CPU,采用ev6前端总线,相当于外频的两倍,也就是133外频时,AMD 462脚的CPU的FSB是266,使用DDR266内存和他搭配就刚刚好,如果用两条DDR266做成双通道,虽然内存有533的传输速度,但对于 266的FSB,作用不大,所以双通道内存对CPU的帮助不明显。

新的AMD 754/939 64位CPU,内部就集成了内存管理器(以前内存管理器在主板心片里),所以AMD 64位CPU的前端总线FSB频率与CPU实际频率一致。

就是前端总线的意思,800的U用在533的板上这个U就降到533的状态下使用,DDR400也是只有DDR266的速度

前端总线(FSB)频率(即总线频率)是直接影响CPU与内存直接数据交换速度

CPU主频=总线频率*倍频

外频与前端总线(FSB)频率的区别:前端总线的速度指的是数据传输的速度,外频是CPU与主板之间同步运行的速度。

所以用FSB是533的主版应该可以用!

fsb是速度。能不能上要看总线频率

FSB(前端总线)front side bus

在PC 内部,一个设备与另一个设备通过系统总线(Bus)传递数字信号。CPU可以通过前端总线(FSB)与内存、显卡及其他设备通信。FSB频率越快,处理器在单位时间里得到更多的数据,处理器利用率越高。

前端总线频率直接影响CPU与内存直接数据交换的总线速度。由于采用了特殊的技术,使存在于CPU与内存(CPU通过北桥的内存管理器与内存交换数据)的总线能够在一个时钟周期内完成2次甚至4次传输,因此相当于频率提升了好几倍。(即是CPU外频数倍。)

Intel和AMD在FSB上采用的技术不同。

Intel FSB频率=CPU 外频*4

例如:2.4C 外频200MHz, FSB频率800MHz

AMD FSB频率=CPU外频*2

例如:Athlon XP 2500+ (Barton)外频 166MHz,FSB频率333MHz 。

FSB带宽表示FSB的数据传输速度,单位MB/s或GB/s 。

FSB带宽=FSB频率*FSB位宽/8,现在FSB位宽都是64位。

例如:P4 2.0A:FSB带宽=400MHz*64bit/8=3.2GB/s 。

一般就INTEL的U来说400的上266

533的上333


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11316636.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-15
下一篇 2023-05-15

发表评论

登录后才能评论

评论列表(0条)

保存