libevent 基础概念

本文参照《libevent参考手册》做的笔记,如有错,感谢指正!(以后文章要写在word文档里,然后复制到博客上,刚才写的文章是网络原因还是怎么了没有保存好,就没了!一次心痛的教训。咳咳咳…) 

简要:

利用libevent编写服务端程序,主要有3部分

1.base = event_base_new();创建主通知链base

2.listener_event = event_new(); 创建要监听的事件,

   event_add();并将其加入到主通知链中;

   event_free(); 释放由event_new申请的结构体

3.event_base_dispatch()//主循环

bufferevent内容只写了一点,先占坑,后续补上笔记】

1. Libevent组件

libevent 由下列组件构成:

� evutil:用于抽象不同平台网络实现差异的通用功能。

� event event_baselibevent 的核心,为各种平台特定的、基于事件的非阻塞IO 

端提供抽象API,让程序可以知道套接字何时已经准备好,可以读或者写,并且处理基

本的超时功能,检测OS 信号。

� bufferevent:为libevent 基于事件的核心提供使用更方便的封装。除了通知程序套接字

已经准备好读写之外,还让程序可以请求缓冲的读写操作,可以知道何时IO 已经真正

发生。(bufferevent 接口有多个后端,可以采用系统能够提供的更快的非阻塞IO 方式,

Windows 中的IOCP。)

� evbuffer:在bufferevent 层之下实现了缓冲功能,并且提供了方便有效的访问函数。

� evhttp:一个简单的HTTP 客户端/服务器实现。

� evdns:一个简单的DNS 客户端/服务器实现。

� evrpc:一个简单的RPC 实现。

2. Event_base结构体

使用libevent 函数之前需要分配一个或者多个event_base 结构体。每个event_base 结构

体持有一个事件集合,可以检测以确定哪个事件是激活的

如果设置event_base 使用锁,则可以安全地在多个线程中访问它。然而,其事件循环只能

运行在一个线程中。如果需要用多个线程检测IO,则需要为每个线程使用一个event_base

每个event_base 都有一种用于检测哪种事件已经就绪的“方法”,或者说后端。可以识别的

方法有:

� select

� poll

� epoll

� kqueue

� devpoll

� evport

� win32

3. Event_base的建立与释放

代码:

struct event_base *event_base_new(void);

void event_base_free(struct event_base *base);

event_base_new()函数分配并且返回一个新的具有默认设置的event_base。函数会检测

环境变量,返回一个到event_base 的指针。如果发生错误,则返回NULL。选择各种方法

时,函数会选择OS 支持的最快方法。

使用完event_base 之后,使用event_base_free()进行释放。

4. Libevent事件集合

libevent 的基本操作单元是事件。每个事件代表一组条件的集合,这些条件包括:

� 文件描述符已经就绪,可以读取或者写入

� 文件描述符变为就绪状态,可以读取或者写入(仅对于边沿触发IO

� 超时事件

� 发生某信号

� 用户触发事件

所有事件具有相似的生命周期:

调用libevent 函数设置事件并且关联到event_base 之后,事件进入“已初始化(initialized)”状态

此时可以将事件添加到event_base 中,这使之进入“未决(pending)”状态

在未决状态下,如果触发事件的条件发生(比如说,文件描述符的状态改变,或者超时时间到达),则事件进入“激活(active)”状态,(用户提供的)事件回调函数将被执行

如果配置为“持久的(persistent)”,事件将保持为未决状态

否则,执行完回调后,事件不再是未决的状态

删除操作可以让未决事件成为非未决(已初始化)的状态

添加操作可以让非未决事件再次成为未决的状态

5. libEvent创建事件

代码:

struct event *event_new(struct event_base *base, evutil_socket_t fd,    short what, event_callback_fn cb,    void *arg);

void event_free(struct event *event);

使用event_new()接口创建事件

event_new()试图分配和构造一个用于base 的新的事件。

what 参数是上述标志的集合。

如果fd 非负,则它是将被观察其读写事件的文件。

事件被激活时,libevent 将调用cb 函数,

传递这些参数:

文件描述符fd,表示所有被触发事件的位字段,

以及构造事件时的arg 参数。

发生内部错误,或者传入无效参数时,event_new()将返回NULL

所有新创建的事件都处于已初始化和非未决状态,调用event_add()可以使其成为未决的。

要释放事件,调用event_free()。对未决或者激活状态的事件调用event_free()是安全

的:在释放事件之前,函数将会使事件成为非激活和非未决的。

代码:

在非未决的事件上调用event_add()将使其在配置的event_base 中成为未决的。成功时

函数返回0,失败时返回-1。如果tv NULL,添加的事件不会超时。否则,tv 以秒和微秒指定超时值。如果对已经未决的事件调用event_add(),事件将保持未决状态,并在指定的超时时间被重新调度。

事件标记

� EV_TIMEOUT

这个标志表示某超时时间流逝后事件成为激活的。构造事件的时候,EV_TIMEOUT 标志是

被忽略的:可以在添加事件的时候设置超时,也可以不设置。超时发生时,回调函数的what

参数将带有这个标志。

� EV_READ

表示指定的文件描述符已经就绪,可以读取的时候,事件将成为激活的。

� EV_WRITE

表示指定的文件描述符已经就绪,可以写入的时候,事件将成为激活的。

� EV_SIGNAL

用于实现信号检测,请看下面的“构造信号事件”节。

� EV_PERSIST

表示事件是“持久的”,请看下面的“关于事件持久性”节。

� EV_ET

表示如果底层的event_base 后端支持边沿触发事件,则事件应该是边沿触发的。这个标志

影响EV_READ EV_WRITE 的语义。

事件持久性

默认情况下,每当未决事件成为激活的(因为fd 已经准备好读取或者写入,或者因为超时),

事件将在其回调被执行前成为非未决的。如果想让事件再次成为未决的,可以在回调函数中

再次对其调用event_add()。

然而,如果设置了EV_PERSIST 标志,事件就是持久的。这意味着即使其回调被激活,事

件还是会保持为未决状态。如果想在回调中让事件成为非未决的,可以对其调用event_del

()。

每次执行事件回调的时候, 持久事件的超时值会被复位。因此, 如果具有

EV_READ|EV_PERSIST 标志,以及5秒的超时值,则事件将在以下情况下成为激活的:

� 套接字已经准备好被读取的时候

� 从最后一次成为激活的开始,已经逝去5秒。

只有超时的事件

代码:

#define evtimer_new(base, callback, arg) \

    event_new((base), -1, 0, (callback), (arg))

#define evtimer_add(ev, tv) \

    event_add((ev),(tv))

#define evtimer_del(ev) \

    event_del(ev)

#define evtimer_pending(ev, what, tv_out) \

    event_pending((ev), (what), (tv_out))

为使用方便,libevent 提供了一些以evtimer_开头的宏,用于替代event_*调用来操作纯超

时事件。使用这些宏能改进代码的清晰性。

6. 运行循环事件

一旦有了一个已经注册了某些事件的event_base,就需要让libevent 等待事件并且通知事件的发生。

event_base_loop()

代码:

#define EVLOOP_ONCE     0x01

#define EVLOOP_NONBLOCK 0x02

int event_base_loop(struct event_base *base, int flags);

默认情况下,event_base_loop()函数运行event_base 直到其中没有已经注册的事件为

止。执行循环的时候,函数重复地检查是否有任何已经注册的事件被触发(比如说,读事件

的文件描述符已经就绪,可以读取了;或者超时事件的超时时间即将到达)。如果有事件被

触发,函数标记被触发的事件为“激活的”,并且执行这些事件。

flags 参数标志:

EVLOOP_ONCE,循环将等待某些事件成为激活的,执行激活的事件直到没有更多的事件可以执行,然会返回。

EVLOOP_NONBLOCK,循环不会等待事件被触发:循环将仅仅检测是否有事件已经就绪,可以立即触发,如果有,则执行事件的回调。

event_base_dispatch()

代码:

int event_base_dispatch(struct event_base *base);

event_base_dispatch ( ) 等同于没有设置标志的event_base_loop ( )。所以,event_base_dispatch ( ) 将一直运行, 直到没有已经注册的事件了, 或者调用了event_base_loopbreak()或者event_base_loopexit()为止

7. Bufferevent

很多时候,除了响应事件之外,应用还希望做一定的数据缓冲。比如说,写入数据的时候,

通常的运行模式是:

� 决定要向连接写入一些数据,把数据放入到缓冲区中

� 等待连接可以写入

� 写入尽量多的数据

� 记住写入了多少数据,如果还有更多数据要写入,等待连接再次可以写入

这种缓冲IO 模式很通用,libevent 为此提供了一种通用机制,即buffereventbufferevent

由一个底层的传输端口(如套接字),一个读取缓冲区和一个写入缓冲区组成。与通常的事

件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是, bufferevent 

读取或者写入了足够量的数据之后调用用户提供的回调。

共享公用接口的bufferevent 类型

� 基于套接字的bufferevent:使用event_*接口作为后端,通过底层流式套接字发送或者

接收数据的bufferevent

� 异步IO bufferevent:使用Windows IOCP 接口,通过底层流式套接字发送或者接收数

据的bufferevent(仅用于Windows,试验中)

� 过滤型bufferevent:将数据传输到底层bufferevent 对象之前,处理输入或者输出数据

bufferevent:比如说,为了压缩或者转换数据。

� 成对的bufferevent:相互传输数据的两个bufferevent

回调函数

每个bufferevent 有两个数据相关的回调:一个读取回调和一个写入回调

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值