libevent介绍和使用

简介: libevent 是一个开源的事件通知库,它提供了一个跨平台的抽象接口,libevnet处理的事件包括网络IO事件,定时事件以及信号事件。它可以在不同的操作系统上使用,包括Linux、Windows和Mac OS X等。libevent 的主要目的是提供高效的事件通知机制,用户无需关注平台检测处理事件的机制的差异,只需关注事件的具体处理。它可以用于编写服务器、客户端和其他网络应用程序。

libevent介绍

libevent 是一个开源的事件通知库,它提供了一个跨平台的抽象接口,libevnet处理的事件包括网络IO事件,定时事件以及信号事件。它可以在不同的操作系统上使用,包括Linux、Windows和Mac OS X等。libevent 的主要目的是提供高效的事件通知机制,用户无需关注平台检测处理事件的机制的差异,只需关注事件的具体处理。它可以用于编写服务器、客户端和其他网络应用程序。


libevent使用

网络中有很多说明libevent如何编译的文章,我就不介绍libevent的如何编译安装,首先我们使用一段代码来直观的展示libevent是如何使用的,然后在介绍libevent的流程和libevent的关键API。下面这段代码展示的是服务器接收客户端的消息,并返回消息给客户端。

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include "event2/event.h"
void socket_read_cb(int fd, short events, void *arg);
//接收到客户端的回调处理
void socket_accept_cb(int fd, short events, void* arg)
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    evutil_socket_t clientfd = accept(fd, (struct sockaddr*)&addr, &len);
    evutil_make_socket_nonblocking(clientfd);//设置客户端socket为非阻塞模式
    printf("accept a client %d\n", clientfd);
    struct event_base* base = (struct event_base*)arg;
    struct event *ev = event_new(NULL, -1, 0, NULL, NULL);//分配一个事件
    event_assign(ev, base, clientfd, EV_READ | EV_PERSIST,
                 socket_read_cb, (void*)ev);
    event_add(ev, NULL);//将事件加入到事件管理器中进行管理
}
 //客户端发送数据的回调处理
void socket_read_cb(int fd, short events, void *arg)
{
    char msg[4096];
    struct event *ev = (struct event*)arg;
    int len = read(fd, msg, sizeof(msg) - 1);
    if( len <= 0 )
    {
        printf("client fd:%d disconnect\n", fd);
        event_free(ev);
        close(fd);
        return;
    }
    msg[len] = '\0';
    printf("recv the client msg: %s", msg);
    char reply_msg[4096] = "recvieced msg: ";
    strcat(reply_msg + strlen(reply_msg), msg);
    write(fd, reply_msg, strlen(reply_msg));
}
int socket_listen(int port)
{
    int errno_save;
    evutil_socket_t listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
        return -1;
    evutil_make_listen_socket_reuseable(listenfd);//设置端口和地址为复用
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(port);
    if (bind(listenfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        evutil_closesocket(listenfd);
        return -1;
    }
    if (listen(listenfd, 5) < 0) {
        evutil_closesocket(listenfd);
        return -1;
    }
    evutil_make_socket_nonblocking(listenfd);//设置socket未非阻塞模式
    return listenfd;
}
int main(int argc, char** argv)
{
    int listenfd = socket_listen(8080);
    if (listenfd == -1)
    {
        printf("socket_listen error\n");
        return -1;
    }
    struct event_base* base = event_base_new();//创建事件管理器对象
    struct event* ev_listen = event_new(base, listenfd, EV_READ | EV_PERSIST,
                                        socket_accept_cb, base);//创建监听事件对象
    event_add(ev_listen, NULL);//将监听事件对象加入到事件管理器中进行管理
    event_base_dispatch(base);//消息循环(代码会被阻塞到此处)
    return 0;
}

libevent流程

Libevent框架本质上是一个典型的Reactor模式,所以只需要弄懂Reactor模型,libevent就八九不离十了。

Reactor模式,是一种事件驱动机制。应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。

在Libevent中也是一样,向Libevent框架注册相应的事件和回调函数;当这些事件发生时,Libevent会调用这些回调函数处理相应的事件(I/O读写、定时和信号)。

(1) 创建事件管理器对象

(2) 创建事件对象,并将事件加入到事件管理器对象中

(3) 消息事件循环

25b206689961fa24ecfd77035595b054_6f88c0fddb3b4f34885a4086225467c1.png

在网络事件框架中,我们主要关注2个问题:事件的检测和事件的处理,同样,libevent也主要关注这2个方面,我们使用libevent,可以仅仅使用libevent的事件检测,事件处理的逻辑由我们自己来写,或者事件检测和事件处理都使用libevent提供的方式。

(1)事件的检测

事件管理器对象负责检测事件是否发生,比如是否发生了IO事件(比如是否有客户端的连接,客户端是否发送了数据),定时器事件是否超时等。

(2)事件的处理

当检测到事件发生时,我们应该对事件进行处理,以下是一些示例

a.连接建立时:构建黑白名单,限制最大连接数

b.连接断开时:释放连接和对应的资源

c.数据到达时:数据的处理

因此我们将libevent的API分为这2个方面


libevent API

事件检测相关

事件管理器API

event_base_new();//创建事件管理器对象
event_base_new_with_config();//带配置的事件管理器对象
event_base_free();//销毁事件管理器对象
event_base_loop();//事件循环
event_base_loopbreak();//事件循环退出
event_base_loopexit();//事件循环退出

事件API

event_new();//构建事件对象
event_free();//销毁事件对象
event_add();//注册事件
event_del();//注销事件
event_assign();//修改事件

事件操作API

连接接收

事件监听器对象用于服务器监听客户端的对象,对象为evconnlisterner

evconnlisterner_new();//创建事件监听器对象
evconnlisterner_new_bind();//创建事件监听器对象
evconnlisterner_free();//销毁事件监听器对象
evconnlisterner_set_error_cb();//设置错误回调

读,写,连接操作

libevent的读写和客户端连接操作主要使用bufferevent对象来进行操作的。

bufferevent_socket_new();//创建bufferevent对象
bufferevent_setcb();//设置bufferevent对象的事件回调(读,写,错误回调)
bufferevent_enable();//注册事件类型
bufferevent_disable();//注销事件类型
bufferevent_get_input();//获取读缓冲区
bufferevent_get_output();//获取写缓冲区
bufferevent_read();//读缓冲区
bufferevent_write();//写缓冲区
bufferevent_socket_connect();//连接操作
相关文章
|
存储 缓存 JavaScript
libevent实战的那些坑
libevent实战的那些坑
400 0
libevent实战的那些坑
|
负载均衡 网络协议 C++
VS2010下libevent的如何使用
VS2010下libevent的如何使用
250 0
VS2010下libevent的如何使用
|
Linux
redhat下安装libiconv.so.2
最近公司软件开发环境配置遇到的问题,总是提示:error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory 遇到这样的问题,看一下提示,就是在你的电脑种,找不到libiconv.
3813 0
|
存储 关系型数据库 MySQL
|
存储