【Linux Day17 Libevent库】

Libevent

1.介绍

Libevent 是一个轻量级的开源高性能网络库,有几个显著的亮点:

  • 事件驱动(event-driven),高性能;
  • 轻量级,专注于网络,不如 ACE 那么臃肿庞大;
  • 线程安全。Libevent 使用 libevent_pthreads 库来提供线程安全支持;
  • 跨平台,支持 Windows、Linux、*BSD 和 Mac Os;
  • 支持多种 I/O 多路复用技术, epoll、poll、dev/poll、select 和 kqueue 等;
  • 支持 I/O,定时器和信号等事件;
  • 注册事件优先级; Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、Vomit、Nylon、Netchat 等等。

2.Reactor概述

Reactor 模式直译过来就是反应堆模式,也被称为 Dispatcher 模式。Reactor 是一种事件驱动机制,应用程序需要提供事的接口注册到 Reactor 上,如果有相应的事件发生,Reactor 就会主动分发给对应的接口进行处理。这种机制和好莱坞法则非常契合:不要打电话给我们,我们会打电话给你。
简单来说,Reactor 模式的实现包含三步:

1.注册感兴趣的事件;

2.扫描是否有感兴趣的事件发生;

3.事件发生后做出相应的处理;

3.Libevent的一般使用模型

在这里插入图片描述

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <event.h>

void time_cb(int fd, short event, void *argc)
{
    printf("timer wakeup\n");
}

int main()
{
    struct event_base *base = event_init();
    struct timeval tv;
    tv.tv_sec = 10; // 10s
    tv.tv_usec = 0;
    struct event* time_ev = evtimer_new(base, time_cb, NULL);
    event_add(time_ev, &tv);
    event_base_dispatch(base);
}

处理流程

1) 首先应用程序准备并初始化 event,设置好事件类型和回调函数;

2) 向 libevent 添加该事件 event。对于定时事件,libevent 使用一个小根堆管理,key 为超时时间;对于 Signal 和 I/O 事件,libevent 将其放入到等待链表(wait list)中,这是一 个双向链表结构;

3) 程序调用 event_base_dispatch()系列函数进入无限循环,等待事件,以 select()函数为例; 每次循环前 libevent 会检查定时事件的最小超时时间 tv,根据 tv 设置 select()的最大等 待时间,以便于后面及时处 理超时事件;

​ 当 select()返回后,首先检查超时事件,然后检查 I/O 事件;

​ Libevent 将所有的就绪事件,放入到激活链表中;

​ 然后对激活链表中的事件,调用事件的回调函数执行事件处理;

流程图:

在这里插入图片描述

3.Libevent 支持的事件类型

在这里插入图片描述

4.libevent的主要接口

1.event_base_new

初始化 libevent;对应理解 epoll_create

struct event_base *event_base_new(void);

2.event_new

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

//创建通用事件处理器,初始化event和相应的回调函数

//分配并赋值新的event结构,准备用于添加和删除,即event_add() 或 event_del()

参数1:base表示event base;指定新创建的事件处理器从属的Reactor

参数2:fd,指定与该事件处理器关联的句柄。创建IO事件处理器时,应该给参数传递文件描述符值;创建信号 事件处理器时,应该给参数传递信号值,创建定时事件处理器时,则应该给f参数传递 -1。

参数3:events,需要监控的事件:EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST, EV_ET的位与。

参数4:callback,回调函数

参数5:callback_arg, 回调函数的参数

如果事件包含EV_READ,EV_WRITE,或者他们的组合,那么fd这个文件描述符或者socket将要被监视什么时候可读,什么时候可写。如果事件包含EV_SIGNAL,那么fd就是需要等待事件的号码。如果事件不包含上面的任何标志,那么该事件只能被一个超时触发或者被event_active()手动的激活:这种情况,fd必须是-1。

3.evsignal_new

#define evsignal_new(b, x, cb, arg)    

创建信号事件处理器,相当于 event_new((b), (x), EV_SIGNAL | EV_PERSIST, (cb), (arg))

4.evtimer_new

#define evtimer_new(b, cb, arg) 

创建定时间事件处理器,相当于event_new((b), -1, 0, (cb), (arg))

5.event_set

设置事件

void 
event_set(struct event *ev, evutil_socket_t fd, short events,   void (*callback)(evutil_socket_t, short, void *), void *arg) 

6.event_base_set

建立 event 与 event_base 的映射关系;

int 
event_base_set(struct event_base *eb, struct event *ev); 

7.event_add

注册事件,包括时间事件;相当于 epoll_ctl;

int 
event_add(struct event *ev, const struct timeval *tv);

8.event_del

注销事件

int 
event_del(struct event *ev) ;

9.event_base_loop

进入事件循环

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

event_new 相当于 malloc + event_set + event_base_set

10.event_free

释放事件(包括资源释放)

void
event_free(struct event *ev)

可以简单的理解为对一棵树的操作

在这里插入图片描述

Libevent函数接口图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Libevent的两种使用层次

在这里插入图片描述

1.自己处理I/O

本地服务端代码:

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include <event.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

 
void socket_read_client_cb(int fd, short events, void *arg);

void socket_accept_connect_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);
    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_client_cb, (void*)ev);
    event_add(ev, NULL);
}
 
void socket_read_client_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\n", msg);
 
    char reply_msg[4096] = "sucessfully recvieced msg: ";
    strcat(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);//设置 socket 为地址可重用,即将 socket 属性设为 SO_REUSEADD
    //设置该标志后,Libevent会把该socket设置成reuseable。这样,关闭该socket后,其他socket就能马上使用同一个端口
    
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
    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);//关闭 socke
        return -1;
    }
    evutil_make_socket_nonblocking(listenfd);//设置 socket 为非阻塞
    return listenfd;
}

int main(int argc, char** argv)
{
    int listenfd = socket_listen(6000);
    if (listenfd == -1)
    {
        printf("socket_listen error\n");
        return -1;
    }
    struct event_base* base = event_base_new();
    struct event* ev_listenfd = event_new(base, listenfd, EV_READ | EV_PERSIST,
                                        socket_accept_connect_cb, base);

    event_add(ev_listenfd, NULL);
    event_base_dispatch(base);
 
    return 0;
}


2.I/O处理交给Libevent

待补充

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中安装libevent可以按照以下步骤进行操作: 1. 首先,通过libevent的官网(https://libevent.org/)下载libevent的版本。 2. 下载完成后,解压缩下载的文件。 3. 打开终端,进入解压后的libevent目录。 4. 在终端中运行以下命令,开始编译和安装libevent: ``` ./configure make sudo make install ``` 这些命令将会配置、编译和安装libevent。 5. 安装完成后,可以通过运行以下命令检查libevent是否成功安装: ``` ldconfig -v | grep libevent ``` 如果输出结果中包含libevent.so动态文件的路径,表示安装成功。 以上步骤可以确保在Linux系统中成功安装libevent。如果在编译过程中出现找不到文件的错误,可以尝试以下解决方法: 1. 检查是否已经在/usr/lib目录下找到了libevent.so动态文件。如果没有找到,可以通过创建软连接的方式解决。在终端中运行以下命令: ``` ln -s 文件绝对路径 /usr/lib/libevent.so ``` 这将会创建一个软连接,将文件链接到/usr/lib目录中。 通过以上步骤,您应该能够成功在Linux中安装libevent,并解决相关的错误。希望对您有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【LinuxLinux系统下libevent的安装](https://blog.csdn.net/qq_43411563/article/details/107413703)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Linux环境下,安装libevent](https://blog.csdn.net/xyz_unknown/article/details/128130408)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Linux下编译安装php libevent扩展实例](https://download.csdn.net/download/weixin_38692666/12807205)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值