使用libevent实现进程间通讯

  • libevent概述
    • 起源
    • 获取源码
    • 初识libevent
    • 框架学习-- event_base 重中之重
    • 从思想上出发
    • 一:掏出火箭壳 --->event_base()创建与释放
    • 二:造螺丝 --->event_new()创建与释放
    • 三:拧螺丝 --->event_add()相关函数
    • 四:一节一节造火箭 --->event_base_dispatch()相关函数
    • Demo

libevent概述

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。
链接-来自百度百科: https://baike.baidu.com/item/libevent/.

起源

起初对libevent、libev、libuv等网络库有所耳目,未能拜读,最近在开发公司项目的时,发现底层组件之间交互采用了libevent进行编写,遂对其学习研究。公司中采用libevent 2.0之前的版本进行研发,对比发现,旧版本中很多函数过于冗杂,现对libevent 2.0之后的新版本进行学习研究:

在Libevent2.0之前的版本中,没有event_assign或者event_new函数,而只有event_set函数,该函数返回的event与“当前”base相关联。如果有多个event_base,则还需要调用event_base_set函数指明event与哪个base相关联

获取源码

Github: https://github.com/libevent/libevent

初识libevent

只要是学习编程似乎都逃离不了“hello word”定律!(嗯…真香!)
编译安装libevent源码之后,进入文件sample cd /sample
接下来,我们可以看到libevent官方为我们提供的demo,

vim打开hello-world.c文件查看示例代码。
发现监听端口号为:9995
好,接下来我们开始libevent的奇妙之旅,
使用xshell启动两个本地连接,

  1. 服务端:在上述路径执行 ./hello-world
  2. 客户端:采用nc进行访问 nc 127.0.0.1 9995 9995为上述代码中指定的端口号

    每有客户端注册时 server端将打印 flushed answer,同时,client端打印Hello, World!

框架学习-- 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_base
struct event_base* event_base_new(void)

当然,作为一个优秀的c语言程序员(咳,我还是个菜),要在创建的同时考虑资源释放的问题,
在程序的最后我们需要 event_base_free 进行释放(但我们不得不提前考虑)

// 释放event_base_free
event_base_free(struct event_base* base);

二:造螺丝 —>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);
- tv:参数 Value
NULL: 事件被触发, 对应的回调被调用
tv = {0, n} 设置的时间,在改时间段内检测的事件没被触发, 时间到达之后, 回调函数还是会被调用

函数调用成功返回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 fileint 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 fileint 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 依次执行即可

下一篇将讲述 带数据缓冲区 - Bufferevent …利用Bufferevent 实现网络通讯

详解libevent网络库(一)---框架的搭建相关推荐

  1. 详解Libevent网络库

    项目中要用到libevent,所以就自学了libevent,参考资料为张亮的<libevent源码深度剖析>和<linux高性能服务器编程> Libevent简介 Libeve ...

  2. 详解一个Python库,用于构建精美数据可视化web app,练习做个垃圾分类app

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 醉卧沙场君莫笑,古来征战几人回? ...

  3. Gcc详解以及静态库、动态库生成

    [转] Gcc详解以及静态库.动态库生成 http://www.360doc.com/content/10/0619/14/1795182_33985297.shtml 1.gcc包含的c/c++编译 ...

  4. Windows 网络服务架构系列课程详解(一) ----DHCP服务器的搭建与配置

    Windows 网络服务架构系列课程详解(一) ---------DHCP服务器的搭建与配置   实验背景: 企业网络环境中在没有配置DHCP服务器时,经常会遇到这样的情况,用户不懂怎么去配置IP地址 ...

  5. [Pytorch系列-61]:循环神经网络 - 中文新闻文本分类详解-3-CNN网络训练与评估代码详解

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  6. pillow属于python标准库吗_详解Python图像处理库Pillow常用使用方法

    PIL(Python Image Library)是python的第三方图像处理库,但是由于其强大的功能与众多的使用人数,几乎已经被认为是python官方图像处理库了. 其官方主页为:PIL. PIL ...

  7. Vue.js - Font Awesome字体图标的使用详解(vue-fontawesome库)

    Vue.js - Font Awesome字体图标的使用详解(vue-fontawesome库) Font Awesome 是一个十分优秀的第三方图标库,我之前也写过文章介绍如何在 html 页面中使 ...

  8. 十二、详解计算网络中的流量控制和差错控制、HDLC

    十二.详解计算网络中的流量控制和差错控制 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动 ...

  9. 【React】 详解下一代开源混合应用框架Reapp

    详解下一代开源混合应用框架Reapp reapp官网 转载于:https://www.cnblogs.com/dongdong230/p/4314978.html

最新文章

  1. ultraMaskedEdit使用心得
  2. Hyperledger Fabric 1.0 实战开发系列 第⑤课 fabric 证书解析
  3. java出现errors是什么错误_java中错误(error)和异常(exception)有什么主要区别?
  4. 收到postmaster附件被删除的退信
  5. Java的二十三种设计模式(原型模式(Prototype))
  6. 三天100元从零开始搭建Hadoop集群
  7. Tomcat服务器 Servlet
  8. 【hadoop】java.io.IOException: No FileSystem for scheme: hdfs
  9. Detour hook库x64编译
  10. 西方新冠疫苗有效率的数据
  11. 扇贝有道180919每日一句
  12. java整人的代码_「vbs代码」vbs表白代码+整人代码,抖音vbscript表白代码 - seo实验室...
  13. Spring中bean的生命周期
  14. html5视频自动轮播,HTML5教程 可自动轮播的旋转木马插件
  15. STM32 DCMI OV9655 直接在LCD显示
  16. 台式计算机摄像头怎么打开,如何打开摄像头,教您Win7摄像头怎么打开
  17. SIM900A是什么
  18. Gatekeeper代码导读
  19. 3dmax 2016 2015 2014 2013 vary渲染 视频教程 从入门到精通
  20. 《C语言程序设计教程》(一)

热门文章

  1. HTML常用标签之段落标签
  2. 普通发票模板 html css写的
  3. 2023,“蔚小理”真的经不起更多“事故”了
  4. [Flash]Loading制作
  5. android仿腾讯体育app,腾讯体育app
  6. 嵌入式实时软件平台TOPPERS/ASP简介
  7. R型变压器空载电压和负载电压区别!
  8. 关于apriori算法中置信度、支持度怎么理解的问题
  9. 计算机桌面怎么截图快捷键,电脑截图的快捷键是什么_屏幕截图快捷键_怎么截图快捷键-太平洋IT百科手机版...
  10. 老男孩39期决心书——刘浩海