libevent网络库

1、概述

libevent是一个C语言编写的、轻量级开源高性能事件通知库。作为底层网络库,已经被广泛应用(如:memcached、Vomit、Nylon、Netchat等)。主要有以下几个亮点:

  • 事件驱动(event-driven)
  • 高性能
  • 轻量级,专注网络。
  • 源码精炼,易读
  • 跨平台
  • 支持多种I/O多路复用技术,如epoll、poll、dev/poll、select、kqueue等。
  • 支持I/O,定时器和信号等事件
  • 注册事件优先级

官网地址:https://libevent.org/

2、框架介绍

1)event_base 创建与释放

// 创建event_base
struct event_base* base = event_base_new()
// 释放event_base_free
event_base_free(struct event_base* base);

2)事件创建与释放

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

// 创建新事件
    struct event *event_new(
        struct event_base *base, 
        evutil_socket_t fd, - // 文件描述符 - int  **底层是对epollin与epollout的封装**
        short what, 
        event_callback_fn cb, // 事件的处理回调函数
        void *arg //回调函数传参
); 
// 事件的处理回调函数
    typedef void (*event_callback_fn)(evutil_socket_t, short, void *); 
//    short what
    #define  EV_TIMEOUT         0x01    // 已淘汰(忽略)
    #define  EV_READ            0x02
    #define  EV_WRITE           0x04
    #define  EV_SIGNAL          0x08    //libevent封装了信号相关的操作 SIGNAL
    #define  EV_PERSIST         0x10    // 持续触发
    #define  EV_ET              0x20    // 边沿模式

 最后需要event_free进行释放。

// 创建event_free
void event_free(struct event *event); 

3)event_add()函数

创建事件之后,再将其添加到event_base之前,实际上是不能对其做任何操作的。所以需要使用event_add将事件添加到event_base上去。此时状态由非未决事件->未决事件。

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

函数调用成功返回0,失败返回-1。

4)event_base_dispatch()函数

最后,使用event_base_dispatch函数添加事件循环。

// event_base_dispatch(简化版event_base_loop())
int event_base_dispatch(struct event_base* base);
//等同于没有设置标志的 event_base_loop ( )
//将一直运行,直到没有已经注册的事件了,或者调用 了event_base_loopbreak()或者 event_base_loopexit()为止

5)event_base_loop()函数

// event_base_loop()
    int event_base_loop(struct event_base *base, int flags);
//正常退出返回0, 失败返回-1

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

6)event_base_loopexit()函数

执行当前后退出。

//如果 event_base 当前正在执行激活事件的回调 ,它将在执行完当前正在处理的事件后立即退出
     int event_base_loopexit(
                struct event_base *base,
                const struct timeval *tv
                );
//参数struct timeval *tv
            struct timeval {
                   long   tv_sec;                    
                   long   tv_usec;            
            };

7)event_base_loopbreak()函数

立即退出循环

//让event_base 立即退出循环
         int event_base_loopbreak(struct event_base *base);         
//返回值: 成功 0, 失败 -1

8)Demo

用例(采用fifo通信方式,不带缓冲区操作)

/*************************************************************************
    > File Name: read_fifi.c
    > Author: 
    > Mail: 
    > Created Time: 2021年04月19日 星期一 10时24分57秒
 ************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>
#include<event2/event.h>

//读取回调函数
void read_cb(evutil_socket_t fd,short what,void *arg)
{
    //读管道
    char buf[1024] = {0};
    int len = read(fd,buf,sizeof(buf));
    printf("data len = %d ,buf = %s\n" ,len,buf);
    printf("read event: %s\n",what &EV_READ ? "Yes":"No");//对what 类型对判断
}

int main()
{
   unlink("libeventfifo");
    //创建有名管道
    mkfifo("libeventfifo",0664);
    //open File

    int fd = open("libeventfifo",O_RDONLY | O_NONBLOCK);

    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }
    //读管道
    struct event_base* base = NULL;
    base = event_base_new();

    //创建事件
    struct event* ev = NULL;
    ev = event_new(base,fd,EV_READ | EV_PERSIST,read_cb,NULL);

    // 添加事件
    event_add(ev,NULL);

    //事件循环
    event_base_dispatch(base);

    //释放资源
    event_free(ev);

    event_base_free(base);
    close(fd);
    return 0 ;
}
/*************************************************************************
    > File Name: write_fifi.c
    > Author: 
    > Mail: 
    > Created Time: 2021年04月19日 星期一 10时24分43秒
 ************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>
#include<event2/event.h>

//读取回调函数
void write_cb(evutil_socket_t fd,short what,void *arg)
{
    //写管道
    char buf[1024] = {0};
    int len = read(fd,buf,sizeof(buf));
    static int num = 999;
    sprintf(buf,"hello world == %d \n" ,num);
    write(fd,buf,strlen(buf)+1);
}

int main()
{
    int fd = open("libeventfifo",O_WRONLY | O_NONBLOCK);
    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }
    struct event_base * base = NULL;
    base = event_base_new();

    struct event* ev = NULL;

    ev = event_new(base,fd,EV_WRITE,write_cb,NULL);

    event_add(ev,NULL);

    event_base_dispatch(base);
    
    //释放资源
    event_free(ev);

    event_base_free(base);
    close(fd);
    return 0 ;
}

用gcc 分别编译文件:

gcc write_fifi.c -o write -levent
gcc read_fifi.c -o read -levent

最后分别执行程序:

./read 
./write 

 

posted @ 2021-04-19 11:12  钟齐峰  阅读(219)  评论(0编辑  收藏  举报