libevent的使用

文章目录

  • libevent封装的框架思想
  • 常用函数分析
  • 使用fifo的读写
  • 未决和非未决
  • bufferevent特性
  • bufferevent函数
  • 客户端和服务器连接和监听
  • libevent实现socket通信


libevent封装的框架思想

libevent框架:1. 创建 event_base		(乐高底座)2. 创建 事件evnet	3. 将事件 添加到 base上	4. 循环监听事件满足5. 释放 event_base1. 创建 event_base		(乐高底座)struct event_base *event_base_new(void);struct event_base *base = event_base_new();2. 创建 事件evnet	常规事件 event	--> event_new(); bufferevent --> bufferevent_socket_new();3. 将事件 添加到 base上	int event_add(struct event *ev, const struct timeval *tv)4. 循环监听事件满足int event_base_dispatch(struct event_base *base);event_base_dispatch(base);5. 释放 event_baseevent_base_free(base);

常用函数分析

创建事件event:struct event *ev;struct event *event_new(struct event_base *base,evutil_socket_t fd,short what,event_callback_fn cb;  void *arg);base: event_base_new()返回值。fd: 绑定到 event 上的 文件描述符what:对应的事件(r、w、e)在		EV_READ		一次 读事件EV_WRTIE	一次 写事件EV_PERSIST	持续触发。 结合 event_base_dispatch 函数使用,生效。cb:一旦事件满足监听条件,回调的函数。typedef void (*event_callback_fn)(evutil_socket_t fd,  short,  void *)	arg: 回调的函数的参数。返回值:成功创建的 event
事件event操作:添加事件到 event_baseint event_add(struct event *ev, const struct timeval *tv);ev: event_new() 的返回值。tv:为NULL,不会超时。意为:一直等到事件被触发,回调函数会被调用。为非0,等待期间,检查事件没有被触发,时间到,回调函数依旧会被调用。将事件从base上拿下int event_del(struct event *ev);ev: event_new() 的返回值。释放事件int event_free(struct event *ev);ev: event_new() 的返回值。

使用fifo的读写

read.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 read_cb(evutil_socket_t fd, short what, void *arg)  
{  // 读管道  char buf[1024] = {0};  int len = read(fd, buf, sizeof(buf));  printf("read event: %s \n", what & EV_READ ? "Yes" : "No");  printf("data len = %d, buf = %s\n", len, buf);  sleep(1);  
}  // 读管道  
int main(int argc, const char* argv[])  
{  unlink("myfifo");  //创建有名管道  mkfifo("myfifo", 0664);  // open file  //int fd = open("myfifo", O_RDONLY | O_NONBLOCK);  int fd = open("myfifo", O_RDONLY);  if(fd == -1)  {  perror("open error");  exit(1);  }  // 创建个event_base  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);  // while(1) { epoll();}  // 释放资源  event_free(ev);  event_base_free(base);  close(fd);  return 0;  
}  

write.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 = 0;  sprintf(buf, "hello,world-%d\n", num++);  write(fd, buf, strlen(buf)+1);  sleep(1);  
}  // 写管道  
int main(int argc, const char* argv[])  
{  // open file  //int fd = open("myfifo", O_WRONLY | O_NONBLOCK);  int fd = open("myfifo", O_WRONLY);  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);  ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);  // 添加事件  event_add(ev, NULL);  // 事件循环  event_base_dispatch(base);  // 释放资源  event_free(ev);  event_base_free(base);  close(fd);  return 0;  
}  

未决和非未决

非未决: 没有资格被处理

未决: 有资格被处理,但尚未被处理

event_new --> event ---> 非未决 --> event_add --> 未决 --> dispatch() && 监听事件被触发 --> 激活态 --> 执行回调函数 --> 处理态 --> 非未决 event_add && EV_PERSIST --> 未决 --> event_del --> 非未决

在这里插入图片描述

bufferevent特性

带缓冲区的事件 bufferevent#include <event2/bufferevent.h> 
读:有数据-->读回调函数被调用-->bufferevent_read()-->读数据
写:使用bufferevent_write()-->向写缓冲中写数据-->该缓冲区有数据自动写出-->写完,回调函数被调用

在这里插入图片描述

bufferevent函数

创建、销毁bufferevent:struct bufferevent *ev;struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, enum bufferevent_options options);base: event_basefd:	封装到bufferevent内的 fdoptions:BEV_OPT_CLOSE_ON_FREE返回: 成功创建的 bufferevent事件对象。void  bufferevent_socket_free(struct bufferevent *ev);
给bufferevent设置回调:对比event:	event_new( fd, callback );  	event_add() -- 挂到 event_base 上。bufferevent_socket_new(base,fd)  bufferevent_setcb( callback )void bufferevent_setcb(struct bufferevent * bufev,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void *cbarg );bufev: bufferevent_socket_new() 返回值readcb: 设置 bufferevent 读缓冲,对应回调  read_cb{  bufferevent_read() 读数据  }writecb: 设置 bufferevent 写缓冲,对应回调 write_cb {  } -- 给调用者,发送写成功通知。  可以 NULLeventcb: 设置 事件回调。   也可传NULLevents: BEV_EVENT_CONNECTEDcbarg:	上述回调函数使用的 参数。event回调函数类型typedef void (*bufferevent_event_cb)(struct bufferevent *bev,  short events, void *ctx);void event_cb(struct bufferevent *bev,  short events, void *ctx){...}read 回调函数类型:typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void*ctx);void read_cb(struct bufferevent *bev, void *cbarg ){.....bufferevent_read();   --- read();}bufferevent_read()函数的原型:size_t bufferevent_read(struct bufferevent *bev, void *buf, size_t bufsize);write 回调函数类型:int bufferevent_write(struct bufferevent *bufev, const void *data,  size_t size);
启动、关闭 bufferevent的 缓冲区:默认:新建的bufferevent的写缓冲是 enable、读缓冲是 disablevoid bufferevent_enable(struct bufferevent *bufev, short events);   启动	通常用来启动bufferevent的read缓冲void bufferevent_disable(struct bufferevent *bufev, short events); 禁用events: EV_READ、EV_WRITE、EV_READ|EV_WRITEvoid bufferevent_get_enabled(struct bufferevent *bufev);获取缓冲区的禁用状态,需要借助&来得到

客户端和服务器连接和监听

客户端:socket();connect(fd,addr,addr_len);int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *address, int addrlen);bev: bufferevent 事件对象(其中封装了fd)address、addresslen:等同于 connect() 的第二个参数和第三个参数创建监听服务器:#include<event2/listener.h>//这个函数相当于socket、bind、listen、accept的作用struct evconnlistener *evconnlistener_new_bind (	struct event_base *base,evconnlistener_cb cb, void *ptr, unsigned flags,int backlog,const struct sockaddr *sa,int socklen);base: event_basecb: 回调函数。 一旦被回调,说明在其内部应该与客户端完成数据读写操作,进行通信。ptr: 回调函数的参数flags: 可识别的标志 LEV_OPT_CLOSE_ON_FREE:释放bufferevent时关闭底层传输端口。这将关闭底层套接字、释放底层bufferevent等LEV_OPT_REUSEABLE:端口服用backlog: listen()的第2个参数。 -1 表最大值sa:服务器自己的地址结构体socklen:服务器自己的地址结构体大小。返回值:成功创建的监听器。回调函数类型:typedef void(*evconnlistner_cb)(struct evconnlistener *listener, evutil_socket_t sock,struct sockaddr* addr, int len, void *ptr);listener: evconnlistener_new_bind函数返回值sock: 用于通信的文件描述符addr: 客户端的IP+端口len: addr的lenptr: 外部ptr传递进来的值释放监听服务器:void evconnlistener_free(struct evconnlistener *lev);

libevent实现socket通信

服务器端
在这里插入图片描述
server.c

#include <stdio.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <string.h>  
#include <event2/event.h>  
#include <event2/listener.h>  
#include <event2/bufferevent.h>  // 读缓冲区回调  
void read_cb(struct bufferevent *bev, void *arg)  
{  char buf[1024] = {0};     bufferevent_read(bev, buf, sizeof(buf));  printf("client say: %s\n", buf);  char *p = "我是服务器, 已经成功收到你发送的数据!";  // 发数据给客户端  bufferevent_write(bev, p, strlen(p)+1);  sleep(1);  
}  // 写缓冲区回调  
void write_cb(struct bufferevent *bev, void *arg)  
{  printf("I'm服务器, 成功写数据给客户端,写缓冲区回调函数被回调...\n");   
}  // 事件  
void event_cb(struct bufferevent *bev, short events, void *arg)  
{  if (events & BEV_EVENT_EOF)  {  printf("connection closed\n");    }  else if(events & BEV_EVENT_ERROR)     {  printf("some other error\n");  }  bufferevent_free(bev);      printf("buffevent 资源已经被释放...\n");   
}  void cb_listener(  struct evconnlistener *listener,   evutil_socket_t fd,   struct sockaddr *addr,   int len, void *ptr)  
{  printf("connect new client\n");  struct event_base* base = (struct event_base*)ptr;  // 通信操作  // 添加新事件  struct bufferevent *bev;  bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);  // 给bufferevent缓冲区设置回调  bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);  bufferevent_enable(bev, EV_READ);  
}  int main(int argc, const char* argv[])  
{  // init server   struct sockaddr_in serv;  memset(&serv, 0, sizeof(serv));  serv.sin_family = AF_INET;  serv.sin_port = htons(9876);  serv.sin_addr.s_addr = htonl(INADDR_ANY);  struct event_base* base;  base = event_base_new();  // 创建套接字  // 绑定  // 接收连接请求  struct evconnlistener* listener;  listener = evconnlistener_new_bind(base, cb_listener, base,   LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,   36, (struct sockaddr*)&serv, sizeof(serv));  event_base_dispatch(base);  evconnlistener_free(listener);  event_base_free(base);  return 0;  
}  

客户端
在这里插入图片描述

#include <stdio.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <string.h>  
#include <event2/bufferevent.h>  
#include <event2/event.h>  
#include <arpa/inet.h>  void read_cb(struct bufferevent *bev, void *arg)  
{  char buf[1024] = {0};   bufferevent_read(bev, buf, sizeof(buf));  printf("fwq say:%s\n", buf);  bufferevent_write(bev, buf, strlen(buf)+1);  sleep(1);  
}  void write_cb(struct bufferevent *bev, void *arg)  
{  printf("----------我是客户端的写回调函数,没卵用\n");   
}  void event_cb(struct bufferevent *bev, short events, void *arg)  
{  if (events & BEV_EVENT_EOF)  {  printf("connection closed\n");    }  else if(events & BEV_EVENT_ERROR)     {  printf("some other error\n");  }  else if(events & BEV_EVENT_CONNECTED)  {  printf("已经连接服务器...\\(^o^)/...\n");  return;  }  // 释放资源  bufferevent_free(bev);  
}  // 客户端与用户交互,从终端读取数据写给服务器  
void read_terminal(evutil_socket_t fd, short what, void *arg)  
{  // 读数据  char buf[1024] = {0};  int len = read(fd, buf, sizeof(buf));  struct bufferevent* bev = (struct bufferevent*)arg;  // 发送数据  bufferevent_write(bev, buf, len+1);  
}  int main(int argc, const char* argv[])  
{  struct event_base* base = NULL;  base = event_base_new();  int fd = socket(AF_INET, SOCK_STREAM, 0);  // 通信的fd放到bufferevent中  struct bufferevent* bev = NULL;  bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);  // init server info  struct sockaddr_in serv;  memset(&serv, 0, sizeof(serv));  serv.sin_family = AF_INET;  serv.sin_port = htons(9876);  inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);  // 连接服务器  bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));  // 设置回调  bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);  // 设置读回调生效  // bufferevent_enable(bev, EV_READ);  // 创建事件  struct event* ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST,  read_terminal, bev);  // 添加事件                       event_add(ev, NULL);  event_base_dispatch(base);  event_free(ev);  event_base_free(base);  return 0;  
}  

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

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

相关文章

c++ 线程概述

C中的线程是并发编程的重要组成部分&#xff0c;它允许程序同时执行多个任务。以下是对C线程的概述&#xff1a; 基本概念&#xff1a; 并发&#xff1a;意味着两个或多个任务同时执行。在单核CPU上&#xff0c;由于只有一个CPU&#xff0c;某一时刻只能执行一个任务&#xff0…

MATLAB 变换

MATLAB 变换&#xff08;Transforms&#xff09; MATLAB提供了用于处理诸如Laplace和Fourier变换之类的变换的命令。转换在科学和工程中用作简化分析和从另一个角度查看数据的工具。 例如&#xff0c;傅立叶变换允许我们将表示为时间函数的信号转换为频率函数。拉普拉斯变换使…

为什么运行vue项目有的是npm run serve 有的是npm run dev

在 Vue.js 项目中&#xff0c;使用 npm run 命令来运行开发服务器是一个常见的做法。然而&#xff0c;具体使用 npm run serve 还是 npm run dev&#xff0c;这取决于项目的配置和所使用的构建工具。 Vue CLI 创建的项目&#xff1a; 如果你使用 Vue CLI 创建一个新项目&#x…

软件测试面试问题汇总

一般软件测试的面试分为三轮&#xff1a;笔试&#xff0c;HR面试&#xff0c;技术面试。 前两轮&#xff0c;根据不同企业&#xff0c;或有或无&#xff0c;但最后一个技术面试是企业了解你“行不行”的关键环节&#xff0c;每个企业都会有的。 在平时的学习、工作中一定要善于…

使用tkinter开发的一款可扫描并删除本地文件敏感词的Windows软件

大致功能&#xff1a;可指定扫描Windows上的某个目录的所有文件&#xff0c;单个文件扫描&#xff0c;目前适配支持的文件后缀有&#xff1a;"pdf"、"txt、"doc"、"docx"&#xff0c;软件是开源的&#xff0c;大家可以在此基础上扩展更多类…

servlet-request(请求)-请求转发

request请求 request 请求index.jsplogin.jspsuccess.jspLoginServletSuccessServlet响应写入用户名和密码测试请求转发success.jsp页面测试请求转发SuccessServlet 页面测试重定向SuccessServlet 页面测试 request 请求 作用&#xff1a;获取浏览器发送过来的数据 组成部分&a…

【数据结构初阶】希尔排序

鼠鼠最近学习了希尔排序&#xff0c;做个笔记&#xff01; 希尔排序也是插入排序的一种捏&#xff01;本篇博客也是用排升序来举例捏&#xff01; 希尔排序是基于直接插入排序的&#xff0c;是由大佬D.L.Shell提出的。 目录 1.希尔排序 1.1.预排序 1.2.直接插入排序 2.希…

自动化运维工具---Ansible

一 Puppet Puppet是历史悠久的运维工具之一。它是一种基础架构即代码(laC)工具&#xff0c;使用户可以定义其基础 架构所需的状态&#xff0c;并使系统自动化以实现相同状态。 Puppet可监视用户的所有系统&#xff0c;并防止任何偏离已定义状态的情况。从简单的工作流程自动…

2023年广东省大学生程序设计竞赛题解

比赛链接&#xff1a;The 2023 Guangdong Provincial Collegiate Programming Contest 文章目录 A. Programming Contest&#xff08;签到&#xff09;B. Base Station Construction&#xff08;单调队列优化dp&#xff09;C. Trading&#xff08;排序&#xff09;D. New House…

代码本地化

目的 代码本地化&#xff08;Localization&#xff09;是指将软件应用程序中的文本、图形、声音和其他内容翻译成特定语言的过程&#xff0c;同时确保这些内容在目标文化中适当地呈现。本地化不仅仅是对文本进行翻译&#xff0c;还包括对日期、时间、数字、货币、排序顺序、文本…

04-19 周四 GitHub CI 方案设计

04-19 周四 GitHub CI 方案设计 时间版本修改人描述2024年4月19日14:44:23V0.1宋全恒新建文档2024年4月19日17:22:57V1.0宋全恒完成部署拓扑结构的绘制和文档撰写 简介 需求 由于团队最近把代码托管在GitHub上&#xff0c;为解决推理、应用的自动化CI的需要&#xff0c;调研了…

最近惊爆谷歌裁员

Python团队还没解散完&#xff0c;谷歌又对Flutter、Dart动手了。 什么原因呢&#xff0c;猜测啊。 谷歌裁员Python的具体原因可能是因为公司在进行技术栈的调整和优化。Python作为一种脚本语言&#xff0c;在某些情况下可能无法提供足够的性能或者扩展性&#xff0c;尤其是在…

leetcode_49.字母异位词分组

49. 字母异位词分组 题目描述&#xff1a;给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan"…

MMC设备

MMC&#xff08;MultiMediaCard&#xff09;是一种闪存卡标准&#xff0c;用于作为便携式设备上的存储媒介&#xff0c;例如数码相机、智能手机、平板电脑、个人数字助理&#xff08;PDA&#xff09;以及其他便携式设备。MMC卡最初是由SanDisk和Siemens AG开发的&#xff0c;并…

2、​​​​​​​FreeCAD模块与核心架构总结

FreeCAD作为一个开源的3D建模软件&#xff0c;其内部架构由多个模块组成&#xff0c;这些模块共同协作以支持软件的各种功能。本总结将基于提供的参考文档&#xff0c;对FreeCAD的核心模块、架构特性以及启动过程进行翻译和详细阐述。 核心模块概览 FreeCAD的核心模块主要包括…

分析:Palo Alto在从SASE向SASO演进中定位不佳

摘要 我们通过上一篇文章&#xff08;Fortinet的愿景——超越SASE&#xff09;中应用于Fortinet的相同框架来回顾Palo Alto Network在网络和网络安全方面的前景。 SASE涉及数据传输的第一英里。不过&#xff0c;随着SASE的发展&#xff0c;投资者还需要考虑中间和最后一英里。…

02——线性表

线性表 基本操作 Initlist(&L):初始化表 Length(L):求表长 LocateElem(L,e):按值查找操作 GetElem(L,i):按位查找操作 ListInsert(&L,i,e):插入操作 ListDelete(&L,i,&e):删除操作 PrintList(L):输出操作 Empty(L):判空操作 DestroyList(&L):销毁操作 顺序…

【JavaScript】数据类型转换

JavaScript 中的数据类型转换主要包括两种&#xff1a;隐式类型转换&#xff08;Implicit Type Conversion&#xff09;和显式类型转换&#xff08;Explicit Type Conversion&#xff09;。 1. 隐式类型转换&#xff08;自动转换&#xff09;&#xff1a; js 是动态语言&…

Docker搭建LNMP+Wordpress的实验

目录 一、项目的介绍 1、项目需求 2、服务器环境 3、任务需求 二、Linux系统基础镜像 三、部署Nginx 1、建立工作目录 2、编写Dockerfile 3、准备nginx.conf配置文件 4、设置自定义网段和创建镜像和容器 5、启动镜像容器 6、验证nginx 三、Mysql 1、建立工作目录…

Kalign 3:大型数据集的多序列比对

之前一直用的是muscle&#xff0c;看到一个文章使用了Kalign&#xff0c;尝试一下吧 安装 wget -c https://github.com/TimoLassmann/kalign/archive/refs/tags/v3.4.0.tar.gz tar -zxvf v3.4.0.tar.gz cd kalign-3.4.0 mkdir build cd build cmake .. make make test su…