【Linux】Libevent库

Libevent——高性能I/O框架库

        底层封装了select,poll,epoll,便于使用

        I/O框架库以库函数的形式,封装了较为底层的系统调用,给应用程序提供了一组更便于使用的接口

特点:1.跨平台,2.统一事件源(I/O事件、信号、定时事件),3.libevent_pthreads库保证线程安全,4.基于Reactor模式(主线程只负责事件检测)

 Libevent框架:事件注册交给libevent,事件循环自动用select、poll、epoll检测事件,检测到后通知libevent调用注册的回调函数。


Libevent使用

使用分为三步:

1.注册事件交给libevent

 struct event_base *实例名= event_init();//struct event_base创建实例,初始化

 struct event *事件名= event_new(实例,信号,事件,回调函数,arg)//需要自己写回调函数

void 回调函数名(int fd, short event, void *arg)
{
   处理方式
}

 event_add(事件名, NULL);

2.启动事件循环,内部自动调用select或poll或epoll

 event_base_dispatch(实例名);

3.处理完成后释放

    event_free(事件名);
    event_base_free(实例名);

其中libevent支持的事件类型有:

#define EV_TIMEOUT 0x01 /* 定时事件 */
#define EV_READ 0x02 /* 可读事件 */
#define EV_WRITE 0x04 /* 可写事件 */
#define EV_SIGNAL 0x08 /* 信号事件 */
#define EV_PERSIST 0x10 /* 永久事件 */

//永久性事件取出检测完后还会放回待检测的链表中,可以一直检测 
/* 边沿触发事件,需要 I/O 复用系统调用支持,比如 epoll */
#define EV_ET 0x20

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <event.h>//libevent
#include <signal.h>//信号
//处理信号事件的回调函数
void signal_cb(int fd, short event, void *arg)
{
    if(event & EV_SIGNAL)//event短整型直接按位与比较
        printf("%d Signal triggered\n",fd);
}
//处理定时事件的回调函数
void timeout_cb(int fd, short event, void *arg)
{
    if(event & EV_TIMEOUT)
       printf("timeout\n");
}
int main()
{
    struct event_base *base = event_init();//struct event_base创建实例,初始化
    assert(base!=NULL);
//1.注册事件
    //定义一个信号事件
    //  event_new(属于的实例,信号,事件,处理事件的回调函数,传给回调函数的参数)
    struct event*signal_event = event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,signal_cb,NULL);
    assert(signal_event!=NULL);
    //添加事件
    event_add(signal_event, NULL);


    //创建定时事件
    //struct event *timeout_event = evtimer_new(base, timeout_cb, NULL);   
    struct event*timeout_event = event_new(base,-1,EV_TIMEOUT,timeout_cb,NULL);
    //等待时长
    struct timeval tv = { 5, 0 }; 
    //添加事件
    event_add(timeout_event, &tv);

//2.启动事件循环
    event_base_dispatch(base);

//3.返回处理后free掉注册信息和实例
    event_free(signal_event);
    event_free(timeout_event);
    event_base_free(base);

    exit(0);
}

当I/O,信号,定时事件的队列都为空,则event_base_dispatch结束,程序退出。

将信号注册为EV_PERSIST永久性事件 ,所以程序不会自动结束(一直有事件需要处理)

 若将定时事件注册为永久性事件,它每隔设定的秒都会调用回调函数


写一个TCP服务器端

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<event.h>
struct mess
{
    struct event * ev;
    //int cout;
};
int create_socket()
void recv_cb(int fd, short ev,void*arg)
{
    struct mess * s = (struct mess*)arg;
    if(ev & EV_READ)
    {
        char buff[128] = {0};
        int n = recv(fd,buff,127,0);
        if(n<=0)
        {
            event_free(s->ev);//关闭时要释放实例,需要获取地址,所以前面弄了一个结构体
            free(s);
            close(fd);
            printf("client close\n");
            return;
        }
        printf("buff=%s\n",buff);
        send(fd,"ok",2,0);
    }
}
void accept_cb(int fd, short ev,void*arg)
{
    struct event_base*base = (struct event_base*)arg;
    if(ev&EV_READ)//生成读事件了
    {
        struct sockaddr_in caddr;
        int len = sizeof(caddr);
        int c = accept(fd,(struct sockaddr*)&caddr,&len);
        if(c<0)return;
        printf("accept c=%d\n",c);
        //用recv_cb处理读事件
        struct event* c_ev = event_new(base,c,EV_READ|EV_PERSIST,recv_cb,base);
        if(c_ev==NULL)
        {
            close(c);
            return;
        }
        event_add(c_ev,NULL);
    }
}
int main()
{
    int sockfd = create_socket()
    assert(sockfd!=-1);
    
    struct event_base*base = event_init();
    assert(base!=NULL);

    //产生事件,用accept_cb处理
    struct event*sock_ev = event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,NULL);
    assert(sock_ev!=NULL);
    event_add(sock_ev, NULL);//事件,超时时间
    
    event_base_dispatch(base);
    event_free(sock_ev);
    event_base_free(base);

    exit(0);
}
//创建套接字
int create_socket()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1)
        return -1;
    struct sockaddr_in addr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)return -1;

    res=listen(sockfd,5);
    if(res==-1)return -1;
    return sockfd;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曦樂~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值