Linux网络编程(8)libeven框架

libevent简介:Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

libevent的使用:在下载安装好了后,包含相应的头文件就可以使用封装好了的一些函数
常用头文件:#include
#include

编译使用到libevent相应函数的时候需要在编译命令后加入 -levent

1.事件处理框架 - event_base
使用 libevent 函数之前需要分配一个或者多个 event_base 结构
体。 每个event_base 结构体持有一个事件集合,可以检测以确定哪
个事件是激活的。

相当于epoll红黑数的树根,位于抽象层,完成对event_base的封装,每个event_base都有一种用于检测哪种事件已经就绪的方法或者说后端

Linux网络编程(8)libeven框架_第1张图片
2.event_base的相应操作
创建
struct event_base* event_base_new(void);
释放
event_base_free(struct event_base*base);
循环监听
event_base_dispatch();
查看event_base封装的后端
const char event_get_supported_methods(void);
char *str[];
const char * event_base_get_method(const struct event_base *base);

libevent的使用流程
1.创建事件处理框架
2.创建事件
3.事件添加到事件处理框架上
4.开始事件循环
5.释放资源

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

#define EVLOOP_ONCE 0x01
事件只会被触发一次
事件没有被触发, 阻塞等
#define EVLOOP_NONBLOCK 0x02
非阻塞 等方式去做事件检测
不关心事件是否被触发了
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
没有事件的时候, 也不退出轮询检测

1 .int event_base_loop(struct event_base base, int flags);
a. 正常退出返回0, 失败返回-1
2. int event_base_dispatch(struct event_base
base);
等同于没有设置标志的 event_base_loop ( )
将一直运行,直到没有已经注册的事件了,或者调用 了
event_base_loopbreak()或者 event_base_loopexit()为止

  1. 循环停止
    struct timeval {
    long tv_usec;
    long tv_sec;
    };
    如果 event_base 当前正在执行激活事件的回调 ,它将在执
    行完当前正在处理的事件后立即退出

    int event_base_loopexit(
    struct event_base *base,
    const struct timeval *tv
    );
    让event_base 立即退出循环
    int event_base_loopbreak(struct event_base *base);

事件创建 - event

  1. 创建新事件
    #define EV_TIMEOUT 0x01 // 废弃
    #define EV_READ 0x02
    #define EV_WRITE 0x04
    #define EV_SIGNAL 0x08
    #define EV_PERSIST 0x10 // 持续触发
    #define EV_ET 0x20 // 边沿模式

typedef void (*event_callback_fn)(evutil_socket_t, short, void *); struct event *event_new(

struct event_base *base,

evutil_socket_t fd, - // 文件描述符 - int short what,

event_callback_fn cb, // 事件的处理动作 void *arg

);

○调用event_new()函数之后, 新事件处于已初始化和非未决状态

2.释放事件

void event_free(struct event *event);

3.设置未决事件

构造事件之后,在将其添加到 event_base 之前实际上是不能对其做任何操作的。使用event_add()将事件添加到event_base, 非未决事件 -> 未决事件.

○int event_add(

struct event *ev,

const struct timeval *tv

);

-tv:
NULL: 事件被触发, 对应的回调被调用

tv = {0, 100}, 如果设置的时间,

在改时间段内检测的事件没被触发, 时间到达之后, 回调函数还是会被调用
函数调用成功返回0, 失败返回-1

4.设置非未决

○int event_del(struct event *ev);

对已经初始化的事件调用 event_del()将使其成为非未决和非激活的。如果事件不是

未决的或者激活的,调用将没有效果。成功时函数返回 0,失败时返回-1。

数据缓冲区 - Bufferevent
1.event2/bufferevent.h
2.bufferevent 理解:

是libevent为IO缓冲区操作提供的一种通用机制
bufferevent 由一个底层的传输端口(如套接字 ), 一个读取缓冲区和一个写入缓冲区组成。

与通常的事件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是, bufferevent 在读取或者写入了足够量的数据之后调用用户提供的回调。

3.回调 - 缓冲区对应的操作
○每个 bufferevent 有两个数据相关的回调
一个读取回调
□从底层传输端口读取了任意量的数据之后 读缓冲区对应的回调会被调用
会调用读取回调(默认)
一个写入回调
输出缓冲区中足够量的数据被清空到底层
传输端口后写入回调会被调用(默认)bufferevent_read();bufferevent_write();

使用 bufferevent

1.创建基于套接字的bufferevent

○可以使用 bufferevent_socket_new()创建基于套接

字的 bufferevent

struct bufferevent *bufferevent_socket_new( struct event_base *base, evutil_socket_t fd,

enum bufferevent_options options

);
options: BEV_OPT_CLOSE_ON_FREE

□释放 bufferevent 时关闭底层传输端口。这将关闭底层套接字,释放底层 bufferevent 等

□参考手册page53 - bufferevent的选项标志
struct bufferevent也是一个 event

成功时函数返回一个 bufferevent,失败则返回NULL。

2.在bufferevent上启动链接

○int bufferevent_socket_connect(

struct bufferevent *bev,

struct sockaddr *address, - server ip和port

int addrlen

);

address 和 addrlen 参数跟标准调用 connect() 的参数相同。如果还没有为bufferevent 设置套接字,调用函数将为其分配一个新的流套接字,并且设置为非阻塞的

如果已经为 bufferevent 设置套接字,调用 bufferevent_socket_connect() 将告知libevent套接字还未连接,直到连接成功之前不应该对其进行读取或者写入操作。连接完成之前可以向输出缓冲区添加数据

3.释放bufferevent操作
○void bufferevent_free(struct bufferevent *bev);
这个函数释放 bufferevent

4.bufferevent读写缓冲区回调操作
typedef void (*bufferevent_data_cb)(
struct bufferevent *bev,
void *ctx
);

typedef void (*bufferevent_event_cb)(
struct bufferevent *bev,
short events,
void *ctx

);

events参数:

EV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_ERROR:操作时发生错误。关于错误的更多信息,请调 用
EVUTIL_SOCKET_ERROR()。
BEV_EVENT_TIMEOUT:发生超时。
BEV_EVENT_EOF:遇到文件结束指示。
BEV_EVENT_CONNECTED:请求的连接过程已经完成
实现客户端的时候可以判断

void bufferevent_setcb(
struct bufferevent *bufev,
bufferevent_data_cb readcb,

–在读回调中读数据
–bufferevent_read() bufferevent_data_cb writecb,
–NULL
bufferevent_event_cb eventcb,
NULL

5.禁用、启用缓冲区

○禁用之后, 对应的回调就不会被调用了

void bufferevent_enable(

struct bufferevent *bufev,

short events

);

void bufferevent_disable(

struct bufferevent *bufev,

short events

);

short bufferevent_get_enabled(

struct bufferevent *bufev

);

可以启用或者禁用 bufferevent 上的 EV_READ、EV_WRITE或者 EV_READ | EV_WRITE 事件。没有启用读取或者写入事件时, bufferevent 将不会试图进行数据读取或者写入。

6.操作bufferevent中的数据

○向bufferevent的输出缓冲区添加数据
int bufferevent_write(
struct bufferevent *bufev,
const void *data,
size_t size
);

○从bufferevent的输入缓冲区移除数据

size_t bufferevent_read( struct bufferevent *bufev, void *data,
size_t size);

链接监听器 - evconnlistener
1.创建和释放evconnlistener

typedef void (*evconnlistener_cb)( struct evconnlistener *listener,
evutil_socket_t sock,
◊用于通信的文件描述符
struct sockaddr *addr,
◊客户端的IP和端口信息

int len,
void *ptr
);

○struct evconnlistener * evconnlistener_new( struct event_base *base, evconnlistener_cb cb,
void *ptr, unsigned flags, int backlog,
evutil_socket_t fd);

○struct evconnlistener *evconnlistener_new_bind( struct event_base *base,

evconnlistener_cb cb, — 接受连接之后, 用户要做的操作 void *ptr, // 给回调传参

unsigned flags, int backlog,

----1: 使用默认的最大值 const struct sockaddr *sa,

---- 服务器的IP和端口信息 int socklen);

两个 evconnlistener_new*()函数都分配和返回一个新的连接监听器对象。连接监听器使 用 event_base

2.启用和禁用 evconnlistener

○int evconnlistener_disable(struct evconnlistener *lev);

○int evconnlistener_enable(struct evconnlistener *lev);

这两个函数暂时禁止或者重新允许监听新连接。

3.调整 evconnlistener 的回调函数

void evconnlistener_set_cb(

struct evconnlistener *lev,

evconnlistener_cb cb,

void *arg

重要函数总结

必须要掌握的函数:

-创建event_base

○struct event_base* event_base_new(void);
○失败返回NULL

-释放event_base

○event_base_free(struct event_base* base);

-事件创建 - 没有缓冲区
○struct event *event_new()

○int event_add(

struct event *ev,

const struct timeval *tv

);

○释放事件

void event_free(struct event *event);

-开始事件循环

○int event_base_dispatch(struct event_base* base);

套接字通信
1.创建带缓冲区的事件

struct bufferevent *bufferevent_socket_new( struct event_base *base, evutil_socket_t fd,

enum bufferevent_options options

);

○给读写缓冲区设置回调

void bufferevent_setcb(
struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg

);

void bufferevent_enable(
struct bufferevent *bufev,
short events

);

2.套接字通信, 客户端连接服务器

○int bufferevent_socket_connect( struct bufferevent *bev,

struct sockaddr *address, - server ip和port int addrlen

);

3.服务器端用的函数

○创建监听的套接字

○绑定

○监听

○接收连接请求

○struct evconnlistener *evconnlistener_new_bind( struct event_base *base, evconnlistener_cb cb,

void *ptr, unsigned flags, int backlog,

const struct sockaddr *sa, int socklen);

操作bufferevent中的数据
○向bufferevent的输出缓冲区添加数据
int bufferevent_write(

struct bufferevent *bufev,

const void *data,

size_t size

);

○从bufferevent的输入缓冲区移除数据

size_t bufferevent_read( struct bufferevent *bufev, void *data,

size_t size

);

你可能感兴趣的:(学习笔记)