libevent实践02:读取标准输入的数据

news2024/9/21 3:25:28

对于libevent的知识一点不了解,通知编写测试代码,发现问题,解决问题,一步一步入门学习。

CMakeLists.txt文件:

project(libevent_project)
cmake_minimum_required(VERSION 3.8)

message(STATUS "lkmao:CMAKE_SOURCE_DIR -- ${CMAKE_SOURCE_DIR}")

set(LIBEVET_INSTALL_PATH "/big/libevent/libevent-2.1.12-stable/_install/")
include_directories(
    ${LIBEVET_INSTALL_PATH}/include 
)

# set(CMAKE_C_COMPILER /arm-gcc/bin/arm-linux-gnueabihf-gcc)
# set(CMAKE_CXX_COMPILER /arm-gcc/bin/arm-linux-gnueabihf-g++)

# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pthread")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -lstdc++")


message(STATUS "lkmao:PROJECT_SOURCE_DIR -- ${PROJECT_SOURCE_DIR}")

# add_executable(main_01 main_01.c)
# target_link_libraries(main_01 ${LIBEVET_INSTALL_PATH}/lib/libevent.so)

add_executable(app main_02.c)
target_link_libraries(app ${LIBEVET_INSTALL_PATH}/lib/libevent.so)

编译脚本文件build.sh:

#!/bin/bash
set -e
rm -rf _build_
mkdir _build_ -p
cmake -S ./ -B _build_
make -C _build_
# ./_build_/main_01
./_build_/app

源码文件main_02.c

源码:

#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.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

struct private_data{
    struct event ev;
    struct timeval tv;
    struct event_base *base;
    char buffer[1024];
};
void stdin_callback(int fd, short event, void *argc)
{
    struct private_data *p = (struct private_data *)argc;    
    memset(p->buffer, 0, sizeof(p->buffer));
    read(fd,p->buffer,sizeof(p->buffer));
    DEBUG_INFO("buffer = %s",p->buffer);
    event_add(&p->ev, &p->tv);
}

int main(int main,char *argv[])
{
    struct private_data *p = malloc(sizeof(struct private_data));
    p->base = event_init();
    p->tv.tv_sec = 100;
    p->tv.tv_usec = 0;
    event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
    event_base_set(p->base, &p->ev);
    event_add(&p->ev, &p->tv);
    event_base_dispatch(p->base);
}

执行结果:

 实验解析:

输入hello然后回车,看到stdin_callback函数被调用,在stdin_callback中调用read,读取标准输入中的数据,并将数据打印到标准输出。

关键代码解析

event_set(&p->ev, STDIN_FILENO, EV_READ, timer_cb,p);

STDIN_FILENO:标准输入文件描述符,就是0

EV_READ:读事件,写事件是EV_WRITE

设置阻塞模式 

前例中设置的是100秒超时,大部分情况下,我们需要没有数据就绪的时候,处于长久等待模式,就是阻塞模式,测试代码如下:

#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.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

struct private_data{
    struct event ev;
    struct event_base *base;
    char buffer[1024];
};
void stdin_callback(int fd, short event, void *argc)
{
    struct private_data *p = (struct private_data *)argc;    
    memset(p->buffer, 0, sizeof(p->buffer));
    read(fd,p->buffer,sizeof(p->buffer));
    DEBUG_INFO("buffer = %s",p->buffer);
    event_add(&p->ev, NULL);
}

int main(int main,char *argv[])
{
    struct private_data *p = malloc(sizeof(struct private_data));
    p->base = event_init();
    //p->ev.ev_base->flags |= EV_BLOCK;
    event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
    event_base_set(p->base, &p->ev);
    event_add(&p->ev, NULL);
    event_base_dispatch(p->base);
}

执行结果 

 

 实验解析:

相比前例,删除了struct timeval tv;将出现tv的地方使用NULL代替即可。

在多线程中使用

源码:

#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.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

struct private_data{
    struct event ev;
    char buffer[1024];
};
struct event_base *base = NULL;
void stdin_callback(int fd, short event, void *argc)
{
    struct private_data *p = (struct private_data *)argc;    
    memset(p->buffer, 0, sizeof(p->buffer));
    read(fd,p->buffer,sizeof(p->buffer));
    DEBUG_INFO("buffer = %s",p->buffer);
    event_add(&p->ev, NULL);
}

void* add_fd_thread(void *arg){
    while(base == NULL){
        sleep(1);
    }
    struct private_data *p = malloc(sizeof(struct private_data));
    event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
    event_base_set(base, &p->ev);
    event_add(&p->ev, NULL);
    while(1){
        sleep(1);
    }
    return NULL;
}

void *run_thread(void *arg){
    int res = 0;
    base = event_init();
    DEBUG_INFO("start");
    do{
        res = event_base_dispatch(base);
        if(res < 0){
            perror("event_base_dispatch");
            DEBUG_INFO("res = %d", res);
            exit(-1);
        }
        DEBUG_INFO("res = %d",res);
    }while(1);
    
    DEBUG_INFO("end");
    return NULL;
}

int main(int main,char *argv[])
{
    pthread_t t1,t2;
    int res = 0;
    res = pthread_create(&t1,NULL,add_fd_thread,NULL);
    if(res < 0){
        perror("1:pthread_create");
        return -1;
    }
    res = pthread_create(&t2,NULL,run_thread,NULL);
    if(res < 0){
        perror("2:pthread_create");
        return -1;
    }
    while(1){
        sleep(1);
    }
    DEBUG_INFO("bye bye");
    return 0;    
}

 测试结果:

在没有将事件添加到base中时,event_base_dispatch一直返回1。这肯定不是我们想要的效果。

 在多线程中增加信号事件

#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>

#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

struct private_data{
    struct event ev;
    char buffer[1024];
};
struct event_base *base = NULL;
void stdin_callback(int fd, short event, void *argc)
{
    struct private_data *p = (struct private_data *)argc;    
    memset(p->buffer, 0, sizeof(p->buffer));
    read(fd,p->buffer,sizeof(p->buffer));
    DEBUG_INFO("buffer = %s",p->buffer);
    event_add(&p->ev, NULL);
}

void* add_fd_thread(void *arg){
    while(base == NULL){
        sleep(1);
    }
    struct private_data *p = malloc(sizeof(struct private_data));
    event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
    event_base_set(base, &p->ev);
    event_add(&p->ev, NULL);
    return NULL;
}
static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
	struct event_base *base = user_data;
	struct timeval delay = { 2, 0 };

	printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

	event_base_loopexit(base, &delay);
}
void *run_thread(void *arg){
    int res = 0;
    struct event *signal_event;
    base = event_init();
    signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
    if (!signal_event || event_add(signal_event, NULL)<0) {
		fprintf(stderr, "Could not create/add a signal event!\n");
		return 1;
	}
    DEBUG_INFO("start");
    do{
        res = event_base_dispatch(base);
        if(res < 0){
            perror("event_base_dispatch");
            DEBUG_INFO("res = %d", res);
            exit(-1);
        }
        DEBUG_INFO("res = %d",res);
    }while(0);
    event_free(signal_event);
	event_base_free(base);
    base = NULL;
    DEBUG_INFO("end");
    return NULL;
}

int main(int main,char *argv[])
{
    pthread_t t1,t2;
    int res = 0;
    res = pthread_create(&t1,NULL,add_fd_thread,NULL);
    if(res < 0){
        perror("1:pthread_create");
        return -1;
    }
    res = pthread_create(&t2,NULL,run_thread,NULL);
    if(res < 0){
        perror("2:pthread_create");
        return -1;
    }
    sleep(1);
    while(1){
        sleep(1);
        if(base == NULL){
            break;
        }
    }
    DEBUG_INFO("bye bye");
    return 0;    
}

 执行结果:

实验解析 

 添加SIGINT事件后,base中监听的事件不为空了,所以它就不会返回了。按下CTRL+C后signal_cb函数被调用,延时两秒后,event_base_dispatch循环返回,返回值为0。当前的知识储备还不知道返回0和返回1的区别,但是至少代码运行看起来是正常了。

小结 

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

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

相关文章

Redis高可用群集---搭建(主从、哨兵、Cluster)

目录 Redis 高可用集群Redis 主从复制Redis 哨兵模式Redis 集群模式 Redis 高可用集群 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redi…

# YourKit Java Profiler 教程

YourKit Java Profiler 教程 文章目录 YourKit Java Profiler 教程本教程软件版本说明YourKitIntelliJ Idea 系统要求探查器体系结构探查器代理探查器用户界面 开始分析集成环境集成IntelliJ Idea 安装插件IntelliJ Idea分析 解决性能问题性能瓶颈优化内存使用内存泄漏垃圾分配…

数据结构 | 双向链表

一、数据结构定义 /* 链表结点 */ typedef int ListType; typedef struct node {ListType data; // 存放整型数据struct node* llink, * rlink; // 指向前驱和后继结点的指针 } *Node;/* 双向链表头结点 */ typedef struct headNode {struct node* head, * tail; // 指向双向链…

IP 扫描程序:轻松发现、扫描和跟踪 IP 空间

什么是 IP 扫描 IP 扫描是实时持续监控网络 IP 地址空间的过程。包括 ICMP ping 扫描和 SNMP 扫描在内的网络协议数量用于扫描网络中的 IP 地址。网络管理员依靠 IP 扫描程序轻松检查和管理 IP 地址空间。使用网络 IP 扫描程序进行 IP 扫描可查看 IP 地址空间利用率和性能。 …

C# 使用CefSharp控件 High DPI问题的解决

使用CefSharp控件&#xff0c;在部分高分辨率的电脑中&#xff08;显示缩放比例非100%&#xff0c;而是120%或者125%等&#xff09;会出现以下一些情况&#xff1a; 显示的页面中出现了黑边&#xff0c;且按钮定位也偏了&#xff0c;比如点击【图层】按钮&#xff0c;需要点击上…

selenium用法

一、请求库selenium selenium是一个自动化测试工具&#xff0c;而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题。操作浏览器模拟人的行为。 下载浏览器驱动&#xff1a;以谷歌浏览器为例---->谷歌浏览器驱动&#xff08;版本号对应&#xff09; …

K8S应用生命周期管理

K8S应用生命周期管理. 1 应用周期管理1.1 资源对象1.1.1 基础知识1.1.2 资源属性 1.2 Pod基础1.2.1 Pod概述1.2.2 简单实践1.2.3 流程解读1.2.4 应用解析1.2.5 初始化容器1.2.6 Sidecar实践1.2.7 静态POD实践 1.3 Pod进阶1.3.1 Pod探测机制1.3.2 命令探测1.3.3 TCP探测1.3.4 HT…

C# +.Net医院检验科LIS系统源码 实验室信息系统源码

实验室信息系统&#xff08;Laboratory Information System&#xff0c;缩写LIS&#xff09;是一类用来处理实验室过程信息的软件。这套系统通常与其他信息系统比如医院信息系统&#xff08;HIS&#xff09;连接。实验室信息系统由多种实验室流程模块构成&#xff0c;这些模块可…

79-基于stm32单片机酒精浓度测量疲劳驾驶检测系统(程序+原理图+元件清单全套资料)...

资料编号&#xff1a;079 功能介绍&#xff1a;采用stm32单片机作为主控CPU&#xff0c;采用MQ3传感器采集酒精浓度&#xff0c;采用红外接触传感器感应驾驶员上车时间&#xff0c;OLED显示酒精浓度和驾驶时间&#xff0c;当酒精浓度超过阈值&#xff08;程序可调&#xff09;&…

【QT】——多线程的使用

目录 基本概念 1.线程类QThread 1.1信号和槽 1.2静态函数 1.3 任务处理函数 2.实例 第一种方式 第二种方式 基本概念 默认的线程在Qt中称之为窗口线程&#xff0c;也叫主线程&#xff0c;负责窗口事件处理或者窗口控件数据的更新子线程负责后台的业务逻辑处理&#xff…

Rocky Linux能否通过其他方法合法地获得RHEL源代码?让我们一起来看看吧

在红帽公司限制对RHEL源代码的访问后&#xff0c;Rocky Linux寻找了替代方案来确保他们可以继续获取所需的源代码并行使他们的权利。他们认为这种限制违反了开源的精神和目的&#xff0c;因此积极寻求解决方案&#xff0c;以维护他们对开源软件的承诺。那么Rocky Linux能否通过…

AOM、VTM初体验及安装tensorflow

AOM、VTM初体验 Cmake cmake的定义是什么 &#xff1f;-----高级编译配置工具 当你用不同的语言或者编译器开发一个项目&#xff0c;各就各位code完之后要生成最终的输出&#xff08;dll 或执行文件&#xff09;&#xff0c;这时候就尴尬了&#xff0c;你要手动去MingGW或者…

Kotlin 1.9 新特性预览:data object (数据单例)

前言 data object (数据单例) 是 Kotlin 1.9 中预定引入的新特性 &#xff0c;但其实从 1.7.20 开始就可以预览了。启动预览需要在 gradle 中升级 KotlinCompileVersion&#xff1a; tasks.withType<KotlinCompile> {kotlinOptions.languageVersion "1.9" }…

四、交换网络实验3——VTP配置

更多网络基础内容可见: 网络基础学习目录及各章节指引 4.6.3 VTP配置 实验目的 学习思科私有协议VTP的配置方法,观察VTP三种工作模式的通信方式 实验工具 Cisco Packet Tracer Student 软件 实验环境 安装模拟器的Windows系统 实验步骤 第一步:根据拓扑图,选择三台同…

老胡的周刊(第097期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 Chat2DB[2] Chat2DB 是一款有开源免费的智能…

二分查找--图文详解

二分查找 1. 什么是二分查找2. 原理3. 例子3.1 当数组长度为奇数3.1 当数组长度为偶数3.3 实现过程 4. 顺序查找与二分查找的区别结束语 1. 什么是二分查找 二分查找也称折半查找&#xff0c;是在一组有序(升序/降序)的数据中查找一个元素&#xff0c;它是一种效率较高的查找方…

chatgpt赋能python:重新配置PyCharm,让你的Python编程更加高效

重新配置PyCharm&#xff0c;让你的Python编程更加高效 PyCharm是一个流行的Python集成开发环境&#xff0c;被广泛用于Python编程。但是&#xff0c;有时候我们需要重新配置PyCharm以适应特定的工作需求或优化其性能&#xff0c;这篇文章将讨论如何重新配置PyCharm&#xff0…

K8S安全管理

1 安全管理 1.1 安全框架 1.1.1 认证框架 学习目标 这一节&#xff0c;我们从 基础知识、认证流程、小结 三个方面来学习。 基础知识 资源操作 用户访问k8s业务应用的流程&#xff1a;方法一&#xff1a;无需api_server认证用户 -- ingress|service -- pod方法二&#xf…

Transformer面试题总结

1.框架 Transformer和seq2seq一样由解码器和编码器组成&#xff0c;用多头注意力替换编码器和解码器架构中最常用的循环层 1.1 编码器&#xff1a;编码器有一堆N6的相同层组成&#xff0c;每一层有两个子层&#xff0c;第一个子层包含多头注意力机制&#xff0c;第二个子层是前…

Spring MVC相关注解运用 —— 中篇

目录 一、RESTful风格支持 1.1 RESTful风格介绍 1.2 postman使用 二、PathVariable 2.1 实例程序 2.2 测试结果 三、PostMapping、GetMapping、PutMapping、DeleteMapping 四、HiddenHttpMethodFilter 4.1 在web.xml配置过滤器 4.2 控制器方法 4.3 JSP页面 4.4 测…