libevent库的使用

视频链接

使用libevent写一个读管道程序

头文件#include <event.h>

  • 创建有名管道文件 mkfifo("fifo.tmp", 0700);
  • 打开管道文件 int fd = open("fifo.tmp", O_RDONLY);
  • 创建事件 struct event ev;
  • 创建事件集合
    • 方法1:event_init();
    • 方法2:struct event_base *base = event_base_new();
      • 此方法需要手动释放事件集合 event_base_free(base);
  • 将文件描述符与事件进行绑定
    • 方法1:其实还是调用的event_assign,只是默认传入了全局的事件集合
      event_set(&ev, fd, EV_READ | EV_PERSIST, fifo_read, NULL);
    • 方法2:可以传入自己创建的事件集合base
      event_assign(&ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, NULL);
    • 必须要写一个回调函数,当 监听事件发生时(即fd可读时),需要进行什么操作 void fifo_read(evutil_socket_t fd, short event, void *arg)
  • 把事件添加到集合中 event_add(&ev, NULL);
  • 开始监听
    • 如果是监听默认的全局事件集合 event_dispatch();
    • 监听自己创建的事件集合base event_base_dispatch(base);

完整代码:编译时要加-levent

//mkfifo
#include <sys/types.h>
#include <sys/stat.h>
//exit
#include <stdlib.h>
//open
#include <fcntl.h>
//read
#include <unistd.h>
//perror
#include <stdio.h>
#include <errno.h>

#include <event.h>

//当监听的事件满足条件时,触发该回调函数,通过该函数读取数据
void fifo_read(evutil_socket_t fd,  short event, void *arg)
{
    char buf[32] = {0};
    int ret = read(fd, buf, sizeof(buf));
    if (-1 == ret)
    {
        perror("read");
        exit(1);
    }
    printf("从管道读取 %s\n", buf);
}
int main()
{
    int ret = mkfifo("fifo.tmp", 0700);
    if (-1 == ret)
    {
        perror("mkfifo");
        exit(1);
    }
    
    int fd = open("fifo.tmp", O_RDONLY);
    if (-1 == fd)
    {
        perror("open");
        exit(1);
    }
    
    //创建事件
    struct event ev;
    //初始化事件集合
    event_init();
    //把fd和ev绑定
            //事件、关联的文件描述符、监听什么事件、回调函数、回调函数的参数
    event_set(&ev, fd, EV_READ | EV_PERSIST, fifo_read, NULL);
    //把事件添加到集合中
    event_add(&ev, NULL);
    //开始监听
    event_dispatch();//死循环 如果集合中没有事件可以监听,则返回
    //一旦有fd可读,就会把集合中所有fd清掉(类似select),因此这里读取到一次就结束
    //如果希望一直监听,那么可以把event设置为EV_PERSIST,使其具有事件持久性
    return 0;
}

使用libevent监听信号

  • 其实只需注意怎样把事件和信号绑定起来:
    event_assign(&ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, &ev);

完整代码:

#include <stdio.h>
#include <signal.h>
#include <event.h>
int signal_count = 0;//记录一下收到多少次信号了
//evutil_socket_t既可以是文件描述符类型,又可以是信号
void signal_handler(evutil_socket_t fd,  short event, void *arg)
{
    struct event *ev = (struct event *)arg;
    printf("收到信号 %d\n", fd);
    signal_count++;
    if (signal_count >= 2)
    {
        //把事件从集合中删除,这样就不会再监听SIGINT信号了,能够正常终止了
        event_del(ev);
    }
}

int main()
{
    //创建事件集合
    struct event_base *base = event_base_new();
    //创建事件
    struct event ev;
    //把事件和信号绑定在一起
    //和event_set相比,只是需要多传一个事件集合对象base。event_set本身就是调用的event_assign
    event_assign(&ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, &ev);//这里把ev传参过去了
    //把事件添加到集合中
    event_add(&ev, NULL);
    //开始监听集合
    //event_dispatch();是监听默认的全局的事件集合
    //这里需要监听的是我们自己创建的事件集合
    event_base_dispatch(base);
    //手动释放事件集合
    event_base_free(base);
    return 0;
}

实现服务器

  • 不用创建事件,有专门的函数自动在连接成功时将cfd加入事件集合

    1. 创建事件集合
    1. 创建套接字
    1. evconnlistener_new_bind函数
    • 传入 事件集合回调函数回调函数参数、flags、最大连接队列长度、套接字、套接字大小
      • flags
        LEV_OPT_CLOSE_ON_FREE 自动关闭套接字
        LEV_OPT_REUSEABLE 端口复用
    • 得到 evconnlistener对象指针
    1. 回调函数:在此执行接收连接后的操作
      读写需要通过bufferevent对象来进行
    • 创建bufferevent对象
      struct bufferevent *bev = bufferevent_socket_new(base, cfd, BEV_OPT_CLOSE_ON_FREE)
    • 怎么读写 (bufferevent对象、读回调函数、写回调、异常回调、参数)
      bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);
    • 设置bufferevent对象的可读
      bufferevent对象创建后默认是关闭读写事件的,这里选择打开读事件,一旦有新数据可读时,就触发 读回调函数
      bufferevent_enable(bev, EV_READ);
    • 具体的读操作:在读回调函数中实现读取数据的操作
      bufferevent_read(bev, buf, sizeof(buf));
    1. 开始监听事件集合
    1. 释放监听对象
      evconnlistener_free(listener)
    1. 释放事件集合

总结:
创建事件和事件集合、绑定事件、添加事件到集合、开启监听。而在使用套接字通信时,事件的创建、绑定和添加步骤被自动执行

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值