【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

待补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/472386.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java IO流之Netty实现聊天通信功能

文章目录 1 Netty1.1 概要设计1.1.1 技术选型1.1.2 数据库设计1.1.3 通信设计1.1.3.1 报文协议格式1.1.3.2 报文交互场景 1.2 Netty简单示例1.2.1 pom.xml1.2.2 发送和接收1.2.3 示例说明1.2.3.1 线程阻塞问题1.2.3.2 服务端和接收端 EventLoopGroup 1.3 Netty中handler概述1.4…

python中字典相关知识点总结

1.字典的定义 字典&#xff1a;在Python中&#xff0c;字典是一系列键-值对。每个键都与一个值相关联&#xff0c;程序员可以通过键来访问与之相关联的值。 实际举例&#xff1a; student{name:xincun,age:18} 通过实例我们可以发现&#xff0c;键-值对是两个相关联的值。指…

Qualcomm AI Hub-示例(二)模型性能分析

文章介绍 模型性能分析&#xff08;Profiling&#xff09; 当模型尝试部署到设备时&#xff0c;会面临许多重要问题&#xff1a; 目标硬件的推理延迟是多少&#xff1f;该模型是否符合一定的内存预算&#xff1f;模型能够利用神经处理单元吗&#xff1f; 通过在云端的物理设…

邮件客户端 Thunderbird 简单配置

1. 基本情况介绍 原来使用的邮箱客户端是 Office 365 自带的 Outlook 365切换原因&#xff1a;新装电脑&#xff0c;发现原 Outlook 中的账号信息无法迁移&#xff0c;需要耗费大量时间手动配置邮箱使用的邮箱&#xff1a;微软 O365 邮箱、qq 邮箱、163 邮箱、公司私有邮箱 …

【计算机网络篇】计算机网络的定义和分类

文章目录 &#x1f354;什么是计算机网络&#x1f5c3;️计算机网络的分类⭐按交换方式分类⭐按使用者分类⭐按传输介质分类⭐按覆盖范围分类⭐按拓扑结构分类 &#x1f6f8;小结 &#x1f354;什么是计算机网络 计算机网络是指将多台计算机或其他网络设备通过通信链路连接起来…

55、服务攻防——数据库安全RedisHadoopMysql未授权访问RCE

文章目录 常见服务应用的安全测试&#xff1a; 配置不当——未授权访问安全机制——特定安全漏洞安全机制——弱口令爆破攻击 应用服务安全测试流程&#xff1a; 判断服务开放情况——端口扫描&组合猜解等 端口扫描&#xff1a;服务开放&#xff0c;绑定端口没开放&#…

关于继承是怎么样的?那当然是很好理解之

本文描述了关于继承的大部分知识&#xff0c;但是并不全&#xff0c;每篇博客之间的知识都有互串&#xff0c;所以需要把几篇文章合起来看&#xff0c;学会融会贯通&#xff01; 温馨提示&#xff1a;使用PC端观看&#xff0c;效果更佳&#xff01; 目录 1.继承是什么 2.什…

es 聚合操作(一)

前言 Elasticsearch除搜索以外&#xff0c;提供了针对ES 数据进行统计分析的功能。聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 衣服品牌的受欢迎程度这些衣服的平均价格、最高价格、最低价格这些衣服的每天、每月销量如何 使用…

Bito插件

此文档只作用于指导性工作&#xff0c;更多资料请自行探索。 1、插件安装与介绍 1.1 插件下载与安装 在idea中搜索&#xff1a;Bito Bito is also available for:​编辑VSCode​编辑JetBrains​编辑CLI 1.2 官方介绍 插件&#xff1a;ChatGPT GPT-4 - Bito AI Code Assista…

LTD267次升级 | 商城升级线下退款功能 • 内容URL生成高清二维码 • 官微名片展示产品视频

1、商城优化退款功能&#xff0c;支持手动退款&#xff1b; 2、内容生成二维码支持高清分辨率&#xff1b; 3、平台版名片小程序产品橱窗支持视频内容&#xff1b; 4、 其他已知问题修复与优化&#xff1b; 01 商城 在本次升级中&#xff0c;我们对商城的退款功能做了改进与…

首席财务官期刊投稿邮箱

《首席财务官》杂志是由国家新闻出版总署批准的金融类期刊。杂志围绕“打造CFO新定义”而展开&#xff0c;定位于“国内国内第一本公开发行的面向CFO人群提供服务的专业资讯媒体”&#xff0c;核心围绕“竞争、资本、运营”三大要点展开&#xff0c;以CFO视角解读“公司金融&am…

Python的内建比较函数cmp比较原理剖析

Python中的cmp()函数用于比较两个对象的大小。 cmp( x, y)&#xff1a;比较2个对象&#xff0c;前者小于后者返回-1&#xff0c;相等则返回0&#xff0c;大于后者返回1. Python的cmp比较函数比较原理 Python的cmp函数可以比较同类型之间&#xff0c;或者不同数据类型之间。然…

Nebula Graph-01-Nebula Graph简介和安装以及客户端连接

前言 NoSQL 数据库 图数据库并不是可以克服关系型数据库缺点的唯一替代方案。现在市面上还有很多非关系型数据库的产品&#xff0c;这些产品都可以叫做 NoSQL。NoSQL 一词最早于上世纪 90 年代末提出&#xff0c;可以解释为“非 SQL” 或“不仅是 SQL”&#xff0c;具体解释要…

初识HOOK框架frida

hook是什么 hook框架是一种技术&#xff0c;用于在运行时拦截和修改应用程序的行为&#xff0c;通过hook&#xff0c;可以劫持应用程序的方法调用、修改参数、篡改返回值等&#xff0c;以达到对应用程序的修改、增强或调试的目的。 常见的hook框架有哪些 Xposed Framework&am…

固态浸压计

Solid State Dip Meter(固态浸没仪/固态浸压计) 是真空管栅极浸入式仪表的固态半导体版本。它是一种用于测量 LC 电路谐振频率的仪器。LC 电路是由电感 (L) 和电容 (C) 组成的电路。当电感的感抗与电容的容抗相互抵消时&#xff0c;这些元件可以谐振于特定频率。 固态浸入式仪…

matlab中Signal Editor定义梯形信号输出矩形信号

matlab中Signal Editor定义梯形信号输出矩形信号&#xff0c;可以通过如下勾选差值数据实现梯形信号输出。

MySQL数据库介绍与部署

背景 MySQL 是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;最初由瑞典公司 MySQL AB 开发&#xff0c;后被 Oracle 公司收购。MySQL 使用标准 SQL 进行查询和管理数据&#xff0c;并支持多种操作系统。它是最流行的开源数据库之一&#xff0c;被…

金属表面缺陷检测设备通常采用计算机视觉技术和机器学习算法

金属表面缺陷检测是在金属制造过程中非常重要的质量控制步骤。它涉及检测金属表面可能存在的各种缺陷&#xff0c;如裂纹、气泡、凹坑、氧化、斑点等。这些缺陷可能会影响金属制品的性能和质量&#xff0c;因此需要及早发现并进行处理。 目前&#xff0c;金属表面缺陷检测通常采…

C++:部分题目

1. 封装、继承、多态 封装&#xff1a;将所需的数据成员&#xff0c;以及对数据的操作方法&#xff08;成员函数&#xff09;&#xff0c;绑定在一起成为类&#xff08;类型&#xff09;&#xff0c;定义该类型的对象时&#xff0c;成员被自动隐藏在对象内部。通过封装可以限定…

模拟算法总述

模拟 1.模拟算法介绍 模拟算法通过模拟实际情况来解决问题&#xff0c;一般容易理解但是实现起来比较复杂&#xff0c;有很多需要注意的细节&#xff0c;或者是一些所谓很”麻烦”的东西。 模拟题一般不涉及太难的算法&#xff0c;一般就是由较多的简单但是不好处理的部分组成…