首页 > 其他分享 >libevent网络库

libevent网络库

时间:2023-06-07 17:24:29浏览次数:57  
标签:struct bufferevent 网络 base 事件 libevent include event

libevent动态库的编译链接

安装过程:

  1. 对.tar.gz包 解压安装
  2. 切换到源码对应的文件夹 cd/lib.... -stable
  3. 可能需要yum install libssl-dev
  4. ./configure 会生成一个Makefile文件
  5. make
  6. make install
  7. 注意看libevent的include lib等文件放在哪

使用gcc编译:

gcc -std=gnu99 -o libo1_test lib01_test.c -I/usr/local/include/ -L /usr/local/lib/ -levent
要-I链接include/头文件目录 ,-L 链接lib文件  libevent相关文件放在这些位置
在这些弄好后,还是会出错
需要在/usr/lib64下创建libevent的链接
ln -s /usr/local/lib/libevent-2.1.so.7 /usr/lib64/libevent-2.1.so.7  即可

为了更简便,输入命令:

export LD_LIBRARY_PATH=/usr/local/lib   #具体文件路径看情况
也可以:/etc/profile  将命令加入到该文件
后面即可直接:
gcc -o bufferevent_client bufferevent_client.c -levent

ibevent的 event_base 事件处理框架

event_base结构体是一个事件的集合,在这个集合里检测那个事件被激活,然后执行事件

事件处理框架通过使用epoll poll select 检测事件

类似boost的io_content的run()

使用:

  1. 创建一个事件处理框架
  2. 创建一个事件
  3. 事件添加进事件处理框架
  4. 开始事件循环
  5. 释放资源

event_base结构体类似epoll句柄

 #include<stdio.h>
 #include<unistd.h>
 #include<event2/event.h>
 #include<event2/util.h> 
 int main(int argc,char* argv[])
 {
  struct event_base* base=event_base_new();//创建事件集合
  const char** str=event_get_supported_methods();
  for(int i=0;str[i]!=NULL;i++)
  {
   puts(str[i]);
  }                                                                                                      event_base_free(base); //释放event_base        event_base_dispatch(base);//事件循环                                             
  return 0;
 }
子进程中event_base

event_base初始化后,fork()创建子进程后,子进程复制父进程的代码资源,同样在子进程中也有struct event_base* base;但是在子进程中要初始化该base event_reinit(base);

创建事件 struct event 没有缓冲区

what主要对应上面的宏定义 事件创建默认水平模式,事件触发调用回调函数处理 void*arg作为回调函数的参数

event_new()创建的事件为非未决状态,通过加入到event_base()为未决状态

非未决:没有资格被处理 未决:有资格但还没被处理

调用事件创建函数创建事件;然后将事件加入到事件处理event_base上

所有新创建的事件都是初始化的,并且非阻塞,调用event_add可以让一个事件变为阻塞。
调用event_free释放event,在事件阻塞或者激活状态下调用event_free是安全的,这个函数会在释放event之前将事件变为非阻塞并且非激活状态。

event_del(struct event* ev);//从event_base中删除事件

当一个事件被触发,在事件对应的回调函数调用前该事件就会变为非阻塞的

事件循环

event_base_dispatch(struct event_base base);* event_base循环处理其事件集

事件在event_base上等待触发,事件被触发后调用回调函数执行,若是事件只触发一次,则被触发后,事件移出event_base。可通过在事件event_new()时,将事件的short what赋值为持续触发:EV_PERSIST

持续触发,只要触发就调用回调函数,处理后有进入event_base处理集

退出事件循环

event_base_loopexit(...base,...tv)可设定多长时间退出事件循环,若是在设定时间退出时,正在执行回调函数,则执行完在退出。

事件在循环中被触发,进入激活状态 调用回调函数,调用后事件又变为非未决状态

event结合管道读写的例子

读管道:

#include<fcntl.h>
#include<stdlib.h>
#include<event2/event.h>
#include<event2/util.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<memory.h>
//管道通信       在读写端有事件触发时回调函数处理
//回调函数,有三个参数
void read_cb(evutil_socket_t fd,short what,void* arg)//会持续读,写端关闭后还是持续读
{
     char buff[1024];
     memset(buff,0,sizeof(buff));
     if(read(fd,buff,sizeof(buff))<0)
     {
       perror("read error");
       exit(1);
     }
     printf("read:%s\n",buff);
 }
 int main(int argc,char* argv[])
 {
     unlink("myfifo");                                                                                                                                                  
     mkfifo("myfifo",0777);//创建管道通信的管道文件
 
     int fd=open("myfifo",O_RDONLY|O_NONBLOCK);//打开管道文件,读端
     if(fd==-1)
     {
        perror("open error");
        exit(1);
     }
     //已经打开管道文件,获得了读端的fd;接下来是把读端的事件加到event_base里,有读端数据触发则处理
     struct event_base* base=event_base_new();
     //创建读端事件       触发读事件后,调用回调函数read_cb
     struct event* ev=event_new(base,fd,EV_READ|EV_PERSIST,read_cb,NULL);
     //添加事件
     event_add(ev,NULL);
     //事件循环
     event_base_dispatch(base);
 
     //释放资源
     event_free(ev);
     event_base_free(base);
     close(fd);
     return 0;
 }

管道写端:

 #include<stdio.h>
 #include<unistd.h>
 #include<sys/stat.h>
 #include<sys/types.h>
 #include<fcntl.h>
 #include<stdlib.h>
 #include<memory.h>
 #include<event2/event.h>
 #include<event2/util.h>
 
 //管道通信       在写端能触发时回调函数处理
 //回调函数,有三个参数
 void write_cb(evutil_socket_t fd,short what,void* arg)
 {
     char*buff="write to fifo";
     size_t size=strlen(buff);
     if(write(fd,buff,size)!=size)                                                                                      
     {
       perror("read error");
       exit(1);
     }
 }
 int main(int argc,char* argv[])
 {
     //先打开读端,再打开写端
     int fd=open("myfifo",O_WRONLY|O_NONBLOCK);//打开管道文件,写端
     if(fd==-1)
     {
        perror("open error");
        exit(1);
     }
     //已经打开管道文件,获得了写端的fd;接下来是把写端的事件加到event_base里,可以写触发则处理
     struct event_base* base=event_base_new();
     //创建写端事件       触发写事件后,调用回调函数write_cb
     struct event* 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;
 }

bufferevent

读缓冲区有数据,触发读事件,在读回调中使用bufferevent_read()读出,写缓冲区有数据会自动发送,触发写回调函数

bufferevent有读写缓冲区,当读缓冲区有数据时,读缓冲区对应的回调函数会被调用,在回调函数中读缓冲区数据

bufferevent_read()

当有数据要发送,调用bufferevent_write()往写缓冲区写入数据,写缓冲区有数据,会自动发送数据,发生数据后,写回调才被调用

bufferevent主要使用在服务端与客户端进行交互通信的fd上

//释放bufferevent:void bufferevent_free(struct bufferevent* bev);
//读写缓冲区的回调函数:
typedef void (*bufferevent_data_cb) (struct bufferevent* bev,void* ctx);
typedef void (*bufferevent_event_cb) (struct bufferevent* bev,short events,void* ctx);

  1. 创建bufferevent事件 bufferevent_socket_new()
  2. bufferevent_setcb()设置读写回调函数
  3. 定义读写回调函数
  4. 在读写回调函数使用bufferevent_read() bufferevent_write()读写

buffer_socket_connect()主要用在客户端要与服务端建立连接

默认ev_write是enable

默认ev_read是关闭的,要使用ev_read先enable开启

server使用bufferevent流程:要监听,bind等(创建前缀的流程)

绑定加监听 evconnlistener_new_bind()返回监听器对象,有连接到来调用回调函数 (listen()函数)

回调函数 类似accept()函数

服务端事件示例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<event2/util.h>
#include<event2/bufferevent.h>
#include<event2/listener.h>
#include<string.h>
//使用bufferevent实现服务端
//读回调
void read_cb(struct bufferevent* bev,void* arg)
{
     char buff[1024]={0};
     bufferevent_read(bev,buff,sizeof(buff));
     printf("接收到:%s\n",buff);
     char* pt="服务端已接收到数据";
     bufferevent_write(bev,pt,strlen(pt)+1);
     puts("服务端已发送数据给客户端");
 }
 //写回调,数据发送出去写回调才会被调用
 void write_cb(struct bufferevent* bev,void* arg)
 {
     puts("数据已发送");
 }
 //事件回调,主要看发生了什么事件
 void event_cb(struct bufferevent* bev,short events,void* arg)
 {
     if(events&BEV_EVENT_EOF)
     {
         puts("连接断开");
     }
 }
 //有连接则调用回调函数处理连接,服务端连接客户端后的fd在回调函数形参上
 //处理连接,将连接间的通信初始化为事件
 void listen_fd(struct evconnlistener*listener,evutil_socket_t fd,struct sockaddr* addr,int len,void* ptr)
 {//把连接通信封装成bufferevent事件
     struct event_base* base=(struct event_base*)ptr;
     //连接通信事件,bufferevent事件关联服务端与客户端连接的fd;在base上
     struct bufferevent* 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,char* argv[])
 {
     struct event_base* base=event_base_new();//事件处理框架
     struct sockaddr_in serveraddr;//服务器IP和端口
     memset(&serveraddr,0,sizeof(serveraddr));
     serveraddr.sin_family=AF_INET;
     serveraddr.sin_port=htons(atoi(argv[1]));
     serveraddr.sin_addr.s_addr=INADDR_ANY;
 
     //绑定加监听接受,调用回调时就有与客户端连接的fd,有连接 则回调,第三个参数是给回调函数传参,传给回调函数的void* ptr
     struct evconnlistener* listen=evconnlistener_new_bind(base,listen_fd,base,
                                   LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,-1,
                                  (struct sockaddr*)&serveraddr,sizeof(serveraddr));
     event_base_dispatch(base);//循环
     evconnlistener_free(listen);
     event_base_free(base);//释放资源
     return 0;
 }
客户端,客户端通过事件event读终端数据,用bufferevent_write发送出去
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<event2/event.h>
#include<event2/bufferevent.h>
#include<string.h>
#include<arpa/inet.h>
 
void read_cb(struct bufferevent* bev,void* arg)
 {
     char buff[1024]={0};
     bufferevent_read(bev,buff,sizeof(buff));
     printf("recv:%s\n",buff);
 }
 void event_cb(struct bufferevent* bev,short events,void* arg)
 {
     if(events&BEV_EVENT_EOF)
     {
         puts("连接断开");
     }else if(events&BEV_EVENT_CONNECTED)
     {
         puts("已经连上");
     }
 }
 void read_terminal(int fd,short what,void* arg) 
 {
     char buf[1024]={0};//event事件读取终端的数据
     int len=read(fd,buf,sizeof(buf));
     //读取到的数据通过bufferevent事件发生出去 
     struct bufferevent* bev=(struct bufferevent*)arg;
     bufferevent_write(bev,buf,len+1);//借用bufferevent将终端数据写到客户端缓冲区
 }
 int main(int argc,char* argv[])
 {
     struct sockaddr_in serveraddr;//服务端IP和port
     memset(&serveraddr,0,sizeof(serveraddr));
     serveraddr.sin_family=AF_INET;
     serveraddr.sin_port=htons(atoi(argv[2]));
     inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);
 
     struct event_base* base=event_base_new();//事件框架
     int fd=socket(AF_INET,SOCK_STREAM,0);
     struct bufferevent* bev=bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
     //将事件连接到服务器
     bufferevent_socket_connect(bev,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
     //给事件设置回调
     bufferevent_setcb(bev,read_cb,NULL,event_cb,NULL);
     bufferevent_enable(bev,EV_READ);
 
     //在事件循环前,可以接收终端输入,输入为event事件,STDIN_FILENO是终端读的文件描述符,监听终端输入,触发读事件
     //把与服务端通信的事件bufferevent传给event的回调函数,通过bufferevent传给服务端
     struct event* ev=event_new(base,STDIN_FILENO,EV_READ|EV_PERSIST,read_terminal,bev);
     event_add(ev,NULL);
 
     //事件循环
     event_base_dispatch(base);
     event_base_free(base);
     return 0;
 }

信号事件

struct event* sig=evsignal_new(base,SIGINT,sigfunc,NULL);//NULL为信号回调函数的void* arg参数

void sig_cb(evutil_socket_t fd,short event,void *arg)
{
    printf("In signal event callback\r\n");
    struct event_base * base = (struct event_base *)arg;
    event_base_loopbreak(base);

}

    struct event_base* base=event_base_new();
    struct event* ev=evsignal_new(base,
        (evutil_socket_t)SIGALRM,
        sig_cb,
        base);
   evsignal_add(ev,NULL);//添加到事件处理

标签:struct,bufferevent,网络,base,事件,libevent,include,event
From: https://www.cnblogs.com/persistencejunjie/p/17463998.html

相关文章

  • Suricata构建网络入侵检测系统(一)
    一、Suricata简介   Suricata是一个免费、开源、成熟、快速、健壮的网络威胁检测引擎。Suricata引擎能够进行实时入侵检测(IDS)、内联入侵预防(IPS)、网络安全监控(NSM)和离线pcap处理。Suricata使用强大而广泛的规则和签名语言来检查网络流量,并提供强大的Lua脚本支持来检......
  • 顶象上榜“网络安全企业科技能力百强”
    最新公布的《2023网络安全企业科技能力报告》显示,顶象在“2023网络安全企业科技能力百强”和“2023网络安全企业有效专利数量百强”等两个榜单中均处于前列。《2023网络安全企业科技能力报告》由中关村网络安全与信息化产业联盟发布,旨在探究网络安全企业的科技实力与科技续航能......
  • P5333 [JSOI2019]神经网络
    P5333[JSOI2019]神经网络SolutionEGF表示有标号排列。对每棵树分别算出划分成\(i\)条链的方案数,记为\(f_i\)。具体地:设\(dp[u][i][0/1/2]\)表示在\(u\)子树内拆分成\(i\)条已结束的链,\(0\):已拼完,无法再延伸\(1\):单点,可继续向上扩展\(2\):长度\(>1\)的链......
  • 2023上半年(下午)网络工程师试题解析
    2023上半年(下午)网络工程师试题解析试题一(20分)某企业办公楼网络拓扑如图1-1所示。该网络中交换机Switch1-Switch4均是二层设备,分布在办公楼的各层,上联采用千兆光纤。核心交换机、防火墙、服务器部署在数据机房,其中核心交换机实现冗余配置。图1-1问题1(4分)该企业办公网络采用172.16.1......
  • 盘点最好的Linux网络监控工具!
    想要成为一名优秀的Linux运维工程师,不仅要具备专业的技能,还需要熟练掌握各种各样的工具,它是我们提高工作效率不可或缺的好助手,本文为大家盘点最好的Linux网络监控工具,快来了解一下吧。1、OpenNMS自从1990年以来,OpenNMS就已经存在了,当时它已称为面向企业和大型网络的面......
  • 【HarmonyOS】【ArkTS】如何使用HTTP网络请求获取动态数据刷新UI界面
    【关键字】HttpRequest、ArkTS、网络数据请求、@ohos.net.http【前言】在使用ArkTS开发HarmonyOS应用时,需要调用HTTP网络请求 @ohos.net.http 动态获取数据,进行UI列表刷新,这想必是应用开发最常见的功能。但是根据官网网络请求的示例代码进行功能开发时,封装方法进行HTTP请求后,返回......
  • 【HarmonyOS】【ArkTS】如何使用HTTP网络请求获取动态数据刷新UI界面
    ​【关键字】HttpRequest、ArkTS、网络数据请求、@ohos.net.http 【前言】在使用ArkTS开发HarmonyOS应用时,需要调用HTTP网络请求 @ohos.net.http 动态获取数据,进行UI列表刷新,这想必是应用开发最常见的功能。但是根据官网网络请求的示例代码进行功能开发时,封装方法进行HTTP......
  • 通过redis学网络(1)-用go基于epoll实现最简单网络通信框架
    本系列主要是为了对redis的网络模型进行学习,我会用golang实现一个reactor网络模型,并实现对redis协议的解析。系列源码已经上传githubhttps://github.com/HobbyBear/tinyredis/tree/chapter1redis的网络模型是基于epoll实现的,所以这一节让我们先基于epoll,实现一个最简单的服......
  • linux ping网络不可达
    一、先使用  ifconfig  命令查看虚拟机是否能上网对应显示如下,代表可以上网 二、查看虚拟机设置,网络适配器配置NAT和桥接模式两种   三、再次ping,显示成功 ......
  • CentOS 安装后的网络设置
    一。在安装minimalCentOS后,启动后输入 root与密码  二。cd进入/etc/sysconfig/network-scripts文件夹 三。vi编辑文件 ifcfg-enp4sp0   我看网上其它是 ifcfg-eth0,因为我的网卡名是 enp4sp0 四。修改内容BOOTPROTO="static"#dhcp改为staticONBOOT="y......