本篇简单记录了libevent的安装过程及基础的先进先出管道Demo,其中demo来自这篇博客,安装过程在这篇博客
实验环境
- 系统:Ubuntu 18.04.3
- libevent版本:libevent-2.1.11-stable
libevent安装
- 从libevent官网下载压缩包并解压;
- 进入libevent目录,依次执行:
sunminming@sunminming:~/libevent-2.1.11-stable$ ./configure
sunminming@sunminming:~/libevent-2.1.11-stable$ make
sunminming@sunminming:~/libevent-2.1.11-stable$ sudo make install
这之后应该能在/usr/local/lib目录下找到libevent相关的动态库;
- 将动态库链接到/usr/lib/目录下:
sunminming@sunminming:/usr/local/lib$ ln -s libevent-2.1.so.7 /usr/lib/libevent-2.1.so.7
- 最后执行ldconfig命令。
先进先出管道Demo
FIFO Demo由两个进程(write和read)组成,具体的代码如下:
- read_fifo.c
//read_fifo.c
#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>
//read callback function
void read_callback(evutil_socket_t fd, short what, void* arg)
{
//read the fifo pipe
char buf[1024] = {0};
int len = read(fd, buf, sizeof(buf));
printf("data len = %d, buf = %s
", len, buf);
printf("read event: %s
", what & EV_READ?"Y":"N");
}
int main(int argc, const char* argv[])
{
//construct and open a fifo pipe
unlink("myfifo");
mkfifo("myfifo", 0664);
int fd = open("myfifo", O_RDONLY|O_NONBLOCK);
if(fd == -1)
{
perror("open error");
exit(1);
}
//read from pipr
struct event_base* base = NULL;
base = event_base_new();
//construct a event
struct event* ev = NULL;
ev = event_new(base, fd, EV_READ, read_callback, NULL);
//add event
event_add(ev, NULL);
//event loop
event_base_dispatch(base);
//free resource
event_free(ev);
event_base_free(base);
close(fd);
return 0;
}
- write_fifo.c
//write_fifo.c
#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>
//callback function
void write_callback(evutil_socket_t fd, short what, void *arg)
{
//write into pipe
char buf[1024] = {0};
static int num = 666;
sprintf(buf, "hello, world == %d
", num);
write(fd, buf, strlen(buf)+1);
}
int main(int argc, const char* argv[])
{
//open the fifo file
int fd = open("myfifo", O_WRONLY|O_NONBLOCK);
if(fd == -1)
{
perror("open error");
exit(1);
}
//construct a event_base
struct event_base* base = NULL;
base = event_base_new();
//construct a event
struct event* ev = NULL;
ev = event_new(base, fd, EV_WRITE, write_callback, NULL);
//add event
event_add(ev, NULL);
//event loop
event_base_dispatch(base);
//free resource
event_free(ev);
event_base_free(base);
close(fd);
return 0;
}
- 分别编译writer.c 及 read.c:
sunminming@sunminming:~/libevent/fifo$ gcc write_fifo.c -o write -levent
sunminming@sunminming:~/libevent/fifo$ gcc read_fifo.c -o read -levent
- 先运行read,在运行write,结果应如下:
sunminming@sunminming:~/libevent/fifo$ ./read
data len = 21, buf = hello, world == 666
read event: Y
libevent相关函数
本节简单介绍上一节中几个libevet函数的抽象功能,不涉及函数源码。
-
struct event_base* event_base_new(void):
这个函数是适用libevent库最先需要调用的,返回一个event_base结构体。event_base结构体是整个libevent的基石,负责跟踪每个事件的状态,哪个事件处于挂起状态(pending)等待唤醒,哪个事件处于活动状态(active)。 -
struct event* event_new(struct event_base* base,
evutil_socket_t fd,
short events,
event_callback_fn callback,
void* callback_arg):
当程序需要对某个文件描述符进行监控时,首先需要调用event_new()函数来创造一个event结构体。在libevent的官网中特别强调,event结构体是定义在堆中的,这是由于需要在任何函数中都能监控每个事件。参数列表如下:- struct event_base* base 这个事件属于(官网上的用词是"attached")event_base结构体;
- evutil_socket_t fd 被监视的文件描述符或者信号等;
- short events 需要监控的具体事件,如上文中的EV_WRITE表示文件描述符可写时,EV_READ表示文件描述符可读时,触发该事件;
- event_callback_fn callback 当事件触发时调用的回调函数;
- callback_arg 传递给回调函数callbakck的参数,值得注意的是,传递给callback函数的参数一共三个:事件描述符fd、触发的具体事件events及该参数callback_arg。
-
int event_add(struct event* ev, const struct timeval *timeout):
创建event结构体之后,调用event_add()来将event对象加入挂起事件列表。之后调用该函数之后,参数列表中的ev才能在事件发生时被触发。参数列表如下:- struct event* ev 监控的事件;
- const struct timeval *timeout:对于加入的事件的最大等待时间,若为NULL则一直等待。
返回0表示调用成功,-1表示失败。
-
int event_base_dispatch(struct event_base* base):
最后开始等待事件被触发,一直会持续到没有任何事件属于base或等待时间结束(默认情况下,一个事件只会被触发一次)。参数列表如下:- struct event_base* base 开始等待的base结构体,其中属于其的事件会处于挂起状态等待被触发到活动状态。