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,一经查实,立即删除!

相关文章

MATLAB 变换

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

软件测试面试问题汇总

一般软件测试的面试分为三轮&#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;并防止任何偏离已定义状态的情况。从简单的工作流程自动…

代码本地化

目的 代码本地化&#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;尤其是在…

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

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

【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…

【数据结构与算法】之五道链表进阶面试题详解!

目录 1、链表的回文结构 2、相交链表 3、随机链表的复制 4、环形链表 5、环形链表&#xff08;||&#xff09; 6、完结散花 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知…

【搜索技能】外链

文章目录 前言一、外链是什么&#xff1f;二、如何进行外链调查&#xff1f;总结 前言 今儿因为在搜索一个很感兴趣的软件&#xff0c;但是软件信息所在的网址非常有限。因此产生了一个念头&#xff1a;我能不能找到所有的包含了或者是引用了这个网站的网站呢? 调查之下&…

解密SSL/TLS:密码套件扫描仪的深度解析(C/C++代码实现)

解密SSL/TLS流量通常是为了分析和审计加密通信&#xff0c;以确保数据传输的安全性和合规性。密码套件扫描仪是实现这一目的的一种工具&#xff0c;它可以提供关于SSL/TLS配置的详细信息&#xff0c;帮助安全专家评估潜在的风险。 SSL/TLS协议基础 SSL/TLS协议是网络安全中不…

select,poll,epoll

在 Linux Socket 服务器短编程时&#xff0c;为了处理大量客户的连接请求&#xff0c;需要使用非阻塞I/O和复用&#xff0c;select&#xff0c;poll 和 epoll 是 Linux API 提供的I/O复用方式。 \selectpollepoll操作方式遍历遍历回调底层实现数组链表哈希表IO效率每次调用都进…

C语言/数据结构——每日一题(环形链表的约瑟夫问题)

一.前言 今天在牛客网上面看到了一道环形链表题&#xff0c;想着和大家们分享一下。可能我有点笨&#xff0c;那道题的链接我没搞好&#xff0c;所以很抱歉&#xff0c;只能麻烦大家们看一下截屏的题目信息了。废话不多数&#xff0c;让我们开始今天的题目分享吧。 二.正文 …

ComfyUI中的图像稀释处理

用下面的节点对图片进行稀释处理&#xff0c;如下 为0表示不变&#xff0c;我设置大一点&#xff0c;设置为0.5看看&#xff0c;如下 图像就暗淡了一些&#xff0c;但是还是有一些彩色的&#xff0c;相当于把它放在水里浸泡了一样&#xff0c;掉色了&#xff0c;这就是稀释&…

公网tcp转流

之前做过几次公网推流的尝试, 今天试了UDP推到公网, 再用TCP从公网拉下来, 发现不行, 就直接改用TCP转TCP了. 中间中转使用的python脚本, 感谢GPT提供技术支持: import socket import threadingdef tcp_receiver(port, forward_queue):"""接收TCP数据并将其放入…