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

news2024/11/19 1:36:46

一 本次实例使用函数简介

事件集合初始化:

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.coloradmin.cn/o/706704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两小时快速入门 TypeScript 基础(二)面向对象

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端&#xff08;Node.js 等&#xff09; &#x1f4c3;个人状态&#xff1a; 2023届本科毕业生&#xff0c;已拿多个前端 offer&#x…

【实战】 二、React 与 Hook 应用:实现项目列表 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表1.新建文件2.状态提升3.新建utils4.Custom Hook 学习内容来源&#xff1a;React React Hook TS 最佳实践-慕课网 相对原教程&#xff0c;我在学习开始时&#xff08;2023.0…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第十二天 12/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

服务运营|MS 论文解读:MIR 增强的Benders 分解用于具有到达率不确定性的多类服务系统人员调度问题

推文作者&#xff1a;王畅&#xff0c;蔡君洋&#xff0c;Guo 编者按 劳动力调度是服务系统运营的一个重要应用场景&#xff0c;当系统中的服务集和客户集异构且客户到达率不确定时&#xff0c;劳动力调度问题会变得特别复杂。本文因此引入了一个两阶段的随机整数规划模型&…

【静态单元格 Objective-C语言】

一、预习QQ动态 1.我们今天,是三、到四个任务,第一个任务,就是这个,预习QQ动态 OK,看到这个效果了吗 这是咱们第一个任务,第一个任务,是实现这么一个效果, 一看这个,就肯定是个啥,UITableView吧, 是不是肯定是一个TableView啊 又能滚动,又能显示一行一行的数据…

Qt QGraphicsScene、QGraphicsView类实现仪表盘

Qt QGraphicsScene、QGraphicsView类实现仪表盘 【1】UI界面设计【2】效果【3】QGraphicsScene简介【4】QGraphicsEllipseItem简介【5】QGraphicsPolygonItem简介【6】QGraphicsLineItem简介【7】QGraphicsView简介【8】仪表源码头文件源码 【1】UI界面设计 【2】效果 【3】QGr…

OpenStack(T版)——对象存储(Swift)服务介绍与安装

文章目录 OpenStack(T版)——对象存储(Swift)服务介绍与安装安装和配置(controller)准备安装和配置Swift对象存储服务组件创建账户 Ring创建容器 Ring创建对象 RingSwift 存储系统的主配置文件修改文件属主 安装和配置(compute)准备配置Swift对象存储服务组件 验证(1)加载环境变…

《程序员的AI书_从代码开始》第二章 手工实现神经网络

文章目录 2.1 感知器2.1.1 从神经元到感知器2.1.2 实现简单的感知器 2.1 感知器 2.1.1 从神经元到感知器 2.1.2 实现简单的感知器 class Perception(object):def __init__(self,eta0.01,iterations10):self.lr etaself.iterations iterationsself.w 0.0self.bias 0.0sel…

Red Hat宣布限制访问源代码,尚有两种方式可获取

日前Red Hat宣布限制访问Red Hat Enterprise Linux(RHEL)源代码&#xff0c;而此举也将影响AlmaLinux 、Rocky Linux 等下游发行版。 随即Rocky Linux发布了名为《Keeping Open Source Open》的博文。文中是这样说的&#xff1a;    Red Hat的**ERP**服务条款 (TOS) 和最终…

dotnet-dump/trace

一、dotnet-dump dotnet tool install -g dotnet-dump ps -ef | grep dotnet export PATH$PATH:$HOME/.dotnet/tools dotnet-dump collect --process-id 31555 #等待最后出输出&#xff1a;Writing full to /root/core_20230701_095230 #分析/root/core_20230701_095230文件 d…

【doxygen】支持 markdown 目录

文章目录 创建章节和子章节配置 doxygen Doxygen 不直接支持 Markdown 的 [toc] 语法。但是&#xff0c;你可以通过以下步骤手动创建目录&#xff1a; 创建章节和子章节 在 Markdown 文件中&#xff0c;使用标题标记&#xff08; # &#xff09;来创建章节和子章节。 Note:…

D2L运行环境问题+anaconda 多环境

环境问题 背景&#xff1a; 换了电脑&#xff0c;当前的电脑原先就装着Python3.9.0 直接pip install d2l & torch can work but when i start the jupyter, it use the anaconda SDK which is 3.6.4 so i need to install the d2l& torch under anaconda python sdk b…

第二章:Fast R-CNN网络详解

(目标检测篇&#xff09;系列文章目录 第一章:R-CNN网络详解 第二章:Fast R-CNN网络详解 第三章:Faster R-CNN网络详解 第四章:YOLO v1网络详解 第五章:YOLO v2网络详解 第六章:YOLO v3网络详解 文章目录 系列文章目录技术干货集锦前言一、摘要二、正文分析 1.引入库2.读…

10个最好的免费PDF阅读器清单分享

PDF&#xff08;便携式文档格式&#xff09;已成为数字文档分发和共享的事实上的标准。要高效地查看、注释和编辑 PDF 文件&#xff0c;可靠的 PDF 阅读器至关重要。在这篇综合文章中&#xff0c;我们将探讨当今可用的前 10 款 PDF 阅读器&#xff0c;评估它们的功能、可用性和…

网工内推 | 云平台运维专场,IE认证优先

01 中科创达 招聘岗位&#xff1a;云平台运维 职责描述&#xff1a; 1、驻场在客户单位处办公&#xff0c;负责H3C品牌的网络、安全、存储、云平台、服务器等软硬件设备的运行监控与管理&#xff0c;包括日常巡检、日常维护等工作&#xff1b; 2、技术支持&#xff0c;为客户…

各牌浏览器设置地址栏显示完整URL

有时候&#xff0c;我们在浏览器的地址栏输入URL后&#xff0c;需要查看完整的URL路径&#xff0c;比如想看到是http协议还是https协议。 目前大多数浏览器都直接将协议头隐藏&#xff0c;需要复制出地址&#xff0c;或者点击地址栏才能看到&#xff0c;比较麻烦。 浏览器支持通…

碳排放预测模型 | Python实现基于LR线性回归和MPR多项式回归的碳排放预测模型

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于LR线性回归和MPR多项式回归的碳排放预测模型 研究内容 预测碳排放 查看汽车模型的数据集并预测其碳排放量。 在这里,使用线性回归和多项式回归进行预测,以找出哪个模型更…

【Python爬虫】Python爬虫三大基础模块(urllib BS4 Selenium)

【Python爬虫】Python爬虫三大基础模块&#xff08;urllib & BS4 & Selenium&#xff09; 文章目录 【Python爬虫】Python爬虫三大基础模块&#xff08;urllib & BS4 & Selenium&#xff09;一、Python爬虫的基本知识1、网络爬虫是什么&#xff1f;1&#xff0…

phpstudy nginx的解析漏洞分析

然后加入/.php 成功执行phpinfo(); 漏洞分析 这是我的生产环境,根据漏洞特性&#xff0c;大概率就是fastcgi的问题。 查看该站点相关的nginx的配置文件 可见 这里的正则处理,将文件传递给fastcgi处理&#xff0c;$fastcgi_script_name会被设置为1.png/.php&#xff0c;然后构…

kafka入门,Leader Partition 负载平衡(十五)

Leader Partition自动平衡 正常请款下&#xff0c;kafka本身会自动把Leader Partition均匀分散在个个机器上&#xff0c;来保证每台机器的读写吞吐量都是均匀的&#xff0c;但是如果某些broker宕机&#xff0c;会导致Leader partition过于集中在其他少部分几台broker上&#xf…