vim打开hello-world.c文件查看示例代码
创造监听端口号为:9995好,接下来我们开始libevent的奇妙之旅,利用xshell启动两个本地连接,
每有客户端注册时 server端将打印 flushed answer,同时,client端打印Hello, World!

须要C/C++ Linux做事器架构师学习资料私信“资料”(资料包括C/C++,Linux,golang技能,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
框架学习-- event_base 重中之重
源码中有这样一句话:The event_base lies at the center of Libevent; every application will have one.
夸年夜的理解为:libevent的天下中,event_base作为万物起源
利用 libevent 函数之前须要分配一个或者多个 event_base 构造体。每个event_base构造体持有一个事宜凑集,可以检测以 确定哪个事宜是激活的。(相称于epoll红黑树的树根)
从思想上出发我们可以把libevent项目想象为造火箭的过程,我们都只是螺丝工,那么造火箭须要做什么?
1. 拿出火箭壳(创建框架)2. 造螺丝 (创建事宜)3. 拧螺丝 (添加事宜)4. 造火箭(事宜循环)
一:取出火箭壳 —>event_base()创建与开释
我们开始第一步:创建一个event_base
// 创建event_basestruct event_base event_base_new(void)
当然,作为一个精良的c措辞程序员(咳,我还是个菜),要在创建的同时考虑资源开释的问题,在程序的末了我们须要 event_base_free 进行开释(但我们不得不提前考虑)
// 开释event_base_freeevent_base_free(struct event_base base);12
二:造螺丝 —>event_new()创建与开释
注:创建事宜:(只针对不带缓冲区event事宜进行讲解)
// 创建新事宜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_freevoid event_free(struct event event);
调用event_new()函数之后, 新事宜处于已初始化和非未决状态 (翻译:螺丝造好了,还没拧到火箭时的状态)
三:拧螺丝 —>event_add()干系函数
创建事宜之后,在将其添加到 event_base 之前实际上是不能对其做任何操作的。利用event_add()将事宜添加到event_base。 (将螺丝拧上去)非未决事宜 -> 未决事宜.
// event_addint event_add(struct event ev, const struct timeval tv);
函数调用成功返回0, 失落败返回-1
设置非未决(作为理解实际中少用)未决事宜 -> 非未决事宜.
//对已经初始化的事宜调用 event_del()将使其成为非未决和非激活的。如果事宜不是未决的或者激活的,调用将没有效果。int event_del(struct event ev); //成功时函数返回 0,失落败时返回-1。
有关于未决态和非未决态的理解:
1. 非未决: 没有资格被处理
2. 未决: 有资格被处理但是还没有处理
四:一节一节造火箭 —>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()为止
关于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//没有事宜的时候, 也不退出轮询检测
关于退失事宜循环函数event_base_loopexit()与event_base_loopbreak():
实行当前退却撤退出 event_base_loopexit()
//如果 event_base 当前正在实行激活事宜的回调 ,它将在实行完当前正在处理的事宜后立即退出 int event_base_loopexit(struct event_base base,const struct timeval tv);//参数struct timeval tvstruct timeval { long tv_sec; long tv_usec; };
立即退出循环 event_base_loopbreak()
//让event_base 立即退出循环 int event_base_loopbreak(struct event_base base); //返回值: 成功 0, 失落败 -1
Demo
末了举个栗子:注:用不带缓冲区操作时的写法:采取fifo通讯的办法
//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>// 回调函数void write_cb(evutil_socket_t fd, short what, void arg){ // write管道 char buf[1024] = {0}; static int num = 666; sprintf(buf, "hello, world == %d\n", num); write(fd, buf, strlen(buf)+1);}int main(int argc, const char argv[]){ // open file int fd = open("myfifo", 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;}
//read_fifo#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", what & EV_READ ? "Yes" : "No");//对what类型对判断}int main(int argc, const char argv[]){ unlink("myfifo"); //创建有名管道 mkfifo("myfifo", 0664); // open file int fd = open("myfifo", 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;}
利用gcc对文件编译 -levevt引用libevent库
gcc read_fifo.c -o read -levent
gcc write_fifo.c -o write -levent
./read ./write 依次实行即可