libevent实践04:监听管道第二季

一 本次实例使用函数简介

事件集合初始化:

struct event_base *event_init(void);

 示例:

struct event_base *base = event_init();

单个事件初始化 

void event_set(struct event *ev, evutil_socket_t fd, short events,void (*callback)(evutil_socket_t, short, void *), void *arg);

evutil_socket_t 的定义,在linux环境就是int类型 

#ifdef _WIN32
#define evutil_socket_t intptr_t
#else
#define evutil_socket_t int
#endif

事件类型

/*** @name event flags** Flags to pass to event_new(), event_assign(), event_pending(), and* anything else with an argument of the form "short events"*/
/**@{*/
/** Indicates that a timeout has occurred.  It's not necessary to pass* this flag to event_for new()/event_assign() to get a timeout. */
#define EV_TIMEOUT	0x01
/** Wait for a socket or FD to become readable */
#define EV_READ		0x02
/** Wait for a socket or FD to become writeable */
#define EV_WRITE	0x04
/** Wait for a POSIX signal to be raised*/
#define EV_SIGNAL	0x08
/*** Persistent event: won't get removed automatically when activated.** When a persistent event with a timeout becomes activated, its timeout* is reset to 0.*/
#define EV_PERSIST	0x10
/** Select edge-triggered behavior, if supported by the backend. */
#define EV_ET		0x20
/*** If this option is provided, then event_del() will not block in one thread* while waiting for the event callback to complete in another thread.** To use this option safely, you may need to use event_finalize() or* event_free_finalize() in order to safely tear down an event in a* multithreaded application.  See those functions for more information.**/
#define EV_FINALIZE     0x40
/*** Detects connection close events.  You can use this to detect when a* connection has been closed, without having to read all the pending data* from a connection.** Not all backends support EV_CLOSED.  To detect or require it, use the* feature flag EV_FEATURE_EARLY_CLOSE.**/
#define EV_CLOSED	0x80

创建事件示例:

    void read_callback(evutil_socket_t fd, short events, void *arg){//process}struct event ev;event_set(&ev,fd,EV_READ | EV_PERSIST,read_callback,NULL);

 添加事件到集合:

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

示例:

event_add(&ev,NULL);

 引出current_base

event_add这里为什么没有调用struct event_base* base呢?看下event_add的实现

int
event_add(struct event *ev, const struct timeval *tv)
{int res;if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {event_warnx("%s: event has no event_base set.", __func__);return -1;}EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);res = event_add_nolock_(ev, tv, 0);EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);return (res);
}

        这里用到了一个成员ev->ev_base,它的定义是struct event_base *ev_base;它是在哪里初始化的呢,应该是在event_set里,event_set的函数原型如下所示

void
event_set(struct event *ev, evutil_socket_t fd, short events,void (*callback)(evutil_socket_t, short, void *), void *arg)
{int r;r = event_assign(ev, current_base, fd, events, callback, arg);EVUTIL_ASSERT(r == 0);
}

这个函数用到了current_base,这是一个全局变量,定义如下:

struct event_base *event_global_current_base_ = NULL;
#define current_base event_global_current_base_

它是在event_init中初始化的。

struct event_base *
event_init(void)
{struct event_base *base = event_base_new_with_config(NULL);if (base == NULL) {event_errx(1, "%s: Unable to construct event_base", __func__);return NULL;}current_base = base;return (base);
}

        从这个函数的定义可知,一个程序只能定义一个struct event_base。因为每次初始化都会给current_base 赋值,所以,我们完全没有必要保存event_init的返回值吗?是这样理解的吗?至少使用当前这几个函数,是这样的。

开始监听:

event_dispatch();

 开始监听,死循环,如果集合中没有事件可以监听,则返回。

int
event_dispatch(void)
{return (event_loop(0));
}

测试代码 

#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
// event_init
//event_set
//event_get
#ifdef _WIN32
#define evutil_socket_t intptr_t
#else
#define evutil_socket_t int
#endif
void event_set(struct event *ev, evutil_socket_t fd, short events,void (*callback)(evutil_socket_t, short, void *), void *arg);void fifo_read_callback(evutil_socket_t fd, short events, void *arg)
{struct event *ev = arg;DEBUG_INFO("%s %s %s ",((events & EV_READ)?"EV_READ":""),((events & EV_PERSIST)?"EV_PERSIST":""),((events & EV_CLOSED)?"EV_CLOSED":""));DEBUG_INFO("read fd = %d events = %d\n", fd, events);char buf[100 + 1];memset(buf, 0, sizeof(buf));int ret = read(fd, buf, sizeof(buf) - 1);if(-1 == ret) {perror("read");exit(-1);}if(ret == 0){if(dup2(fd,fd) < 0){perror("dup2");DEBUG_INFO("fd = %d 已关闭");return;}else{DEBUG_INFO("fd = %d 还没有被关闭");}event_del(ev);close(fd);DEBUG_INFO("fd = %d 已关闭");return ;}DEBUG_INFO("ret = %d,buf = %s\n",ret, buf);
}
char *fifo_name;
int main(int argc, char **argv)
{if(argc < 2){fifo_name = "fifo.tmp";}else{fifo_name = argv[1];}int ret = mkfifo(fifo_name,0666);if(ret == -1){if(errno == EEXIST){DEBUG_INFO("%s exist",fifo_name);}else{perror("mkfifo");exit(-1);}}DEBUG_INFO("create %s ok",fifo_name);int fd = open(fifo_name,O_RDONLY);if(fd == -1){perror("open");exit(-1);}//初始化事件集合struct event_base *base;base = event_init();//初始化事件struct event ev;event_set(&ev,fd,EV_READ | EV_PERSIST ,fifo_read_callback,&ev);//把事件添加到集合中event_add(&ev,NULL);//开始监听,死循环,如果集合中没有事件可以监听,则返回。event_dispatch();DEBUG_INFO("byebye");return 0;
}

测试结果:

        在测试用使用 cat > fifo.tmp将终端输入的数据重定向到管道中,如下所示,不是cat fifo.tmp,如果写成cat fifo.tmp那就是读管道了。如果两个程序同时读管道,那两个程序就阻塞了。

        开始测试,打开两个终端,左边运行测试代码,右边运行cat > fifo.tmp,向管道中写数据,如下所示:

 实验解析:

        集合创建和事件添加前面都有说过,程序运行后,如果还没有运行写管道程序,会卡在open的地方,如果运行了cat > fifo.tmp。会继续向下执行到event_dispatch这里,只要集合base中有在监听,event_dispatch函数就不会返回,此时,在右边的终端中输入hello fifo,并回车,左边读到数据。在fifo_read_callback函数中,当右边的终端关闭管道时,也就是按下CTRL+C,read返回0,此时需调用event_del将事件从集合中删除。

int
event_del(struct event *ev)
{return event_del_(ev, EVENT_DEL_AUTOBLOCK);
}

        该函数中调用了event_del_,在event_del_函数中存在加锁EVBASE_ACQUIRE_LOCK和解锁EVBASE_RELEASE_LOCK,由此可见,这个函数是线程安全的。不需要做额外的线程安全处理。

static int
event_del_(struct event *ev, int blocking)
{int res;struct event_base *base = ev->ev_base;if (EVUTIL_FAILURE_CHECK(!base)) {event_warnx("%s: event has no event_base set.", __func__);return -1;}EVBASE_ACQUIRE_LOCK(base, th_base_lock);res = event_del_nolock_(ev, blocking);EVBASE_RELEASE_LOCK(base, th_base_lock);return (res);
}

小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/3930.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 27.移除元素

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;移除元素 代码&#xff1a; /*思路&#xff1a;双指针问题[3,2,2,3] , val 3src-> [ 3 , 2 , 2 , 3 ]destnums[src] val > srcsrc-> [ 3 , 2 , 2 , 3 ] destnum…

k8s操作命令

系列文章目录 文章目录 系列文章目录一、k8s基础命令1.陈述式资源管理方法&#xff1a;2.基础命令 总结 一、k8s基础命令 1.陈述式资源管理方法&#xff1a; 1.kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 2.kubectl 是官方的CLI命令行工具…

死锁的发生与避免

文章目录 一&#xff1a;概念二&#xff1a;死锁2.1&#xff1a;互斥条件2.2&#xff1a;请求与保持条件2.3&#xff1a;不可剥夺条件2.4&#xff1a;循环等待条件 三&#xff1a;避免死锁问题的发生四&#xff1a;避免死锁的算法 一&#xff1a;概念 死锁是指在一组进程中的各…

QT 简易视频播放器版本1.1

设计Qt界面实现播放、暂停、停止、下一集、上一集、快进、后退、倍速播放、进度调节&#xff0c;音量调节、视频播放列表等功能 先上演示效果&#xff1a; ui界面设计 videoplayer.h #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H#pragma execution_character_set("utf-…

Elastic 推出 Elastic AI 助手

作者&#xff1a;Mike Nichols Elastic 推出了 Elastic AI Assistant&#xff0c;这是一款由 ESRE 提供支持的开放式、生成式 AI 助手&#xff0c;旨在使网络安全民主化并支持各种技能水平的用户。 最近发布的 Elasticsearch Relevance Engine™ (ESRE™) 提供了用于创建高度相…

要从HTML中提取img标签的src属性(图片链接),可以使用正则表达式方式。

1. 定义提取src属性的正则表达式: const srcRegex /<img\s(?:[^>]*?\s)?src\s*\s*(["])((?:[^\1"]|\\\1|.)*?)\1/g 这个正则会匹配类似<img src"http://example.com/1.jpg">中的src属性和括号中的连接。2. 调用字符串的matchAll()方法…

Fiddler抓包工具笔记

一、简介 Fiddler代理相当于中介的角色 快捷键ShiftF5去缓存刷新 二、抓包 1. 设置过滤器 没有设置过滤器的话&#xff0c;会抓所有的包&#xff0c;非常乱会混淆 隐藏包含这些内容的URL 2. 快速定位到需要的包 点击&#xff1a;Webforms菜单 界面分析&#xff1a; …

Proxy error: Could not proxy request 的解决办法

项目启动时报错&#xff0c;如下图 页面错误&#xff1a; 与后台服务地址不一致&#xff0c;修改如下

基于粒子群算法的无约束优化问题求解

基于粒子群算法的无约束优化问题求解 1 引言2 粒子群算法2.1 粒子群优化原理2.2 粒子群算法寻优策略与参数控制粒子群算法流程 3 粒子群算法求解无约束优化问题3.1 粒子群算法求解Sphere函数&#xff08;单峰测试函数&#xff09;3.2 Schwefels Problem 2.26&#xff08;多峰测…

字节跳动算法 提前批offer复盘

作者 | zjwang 面试锦囊之面经分享系列&#xff0c;持续更新中 欢迎后台回复"面试"加入讨论组交流噢 写在前面 北航本硕&#xff0c;非科班对搜索推荐比较感兴趣&#xff0c;平时看的文章比较多&#xff0c;所以聊的比较偏这一块大四时一段五个月的nlp方向实习&…

Linux6.yum,git,gdb

1.yum三板斧 yum list :显示所有能安装的软件。 yum lisy | grep 软件 :搜索软件。 yum install -y :安装软件。 yum remove -y 软件 :删除已经安装的软件。 2.git git clone 仓库网址 :添加仓库&#xff0c;按回车之后。需要输入账户和密码。 git add 文件 :把文件添加…

【计算机网络】物理层

0.概念 1.物理层下面的传输媒体 2.传输方式 3.编码与调制 常用编码 题目 基本调制方法 4.信道的极限容量 题目