Libevent库

  • Libevent概述
  • Libevent使用模型
  • Libevent库使用示例
  • Libevent事件类型和框架结构
  • 使用Libevent完成tcp服务端

Libevent概述

Libevent是开源社区的一款高性能的I/O框架库,使用Libevent的著名案例有:高性能的分布式内存对象缓存软件memcached,Googlo浏览器Chromium的Linux版本。作为一个I/O框架库,Libevent具有如下特点:

  • 跨平台支持 Libevent支持Linux、Unix和Windows
  • 统一事件源 Libevent对I/O事件、信号和定时事件提供统一的处理。
  • 线程安全 Libevent使用libevent_pthread库来提供线程安全支持
  • 基于Reactor模式的实现

Libevent使用模型


libevent主框架提供注册方法,通过事件循环去检测事件就绪并通知libevent框架去调用回调函数

Libevent库使用示例

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<event.h>
#include<assert.h>void signal_cd(int fd,short event,void* arg)
{//fd与事件类型 系统传入,其他参数在argprintf("sig = %d\n",fd);
}
void timeout_ev(int fd,short event,void* arg)
{printf("Time out\n");
}int main()
{//实例初始化struct event_base* base = event_init();assert(base != NULL);//定义信号事件//参数://哪个实例//信号是谁//如何处理信号,回调函数//传入参数struct event* sig_ev = evsignal_new(base,SIGINT,signal_cb,NULL);assert(sig_ev != NULL);//注册//参数://添加事件//事件超时事件event_add(sig_ev,NULL);//定义定时事件struct event* timeout_ev = evtimer_new(base,timeout_cb,NULL);struct timeval tv = {3,0};//指3秒0微秒event_add(timeout_ev,&tv);//启动事件循环event_base_dispatch(base);//阻塞在这里 内部进行循环 并且libevent会根据情况去选择使用select,poll,或eopll//释放事件与实例event_free(sig_ev);event_free(timeout_ev);event_base_free(base);
}

编译代码
直接编译会显示错误,需要链接libevent库

运行查看

Libevent事件类型和框架结构



设置事件,将事件添加至libevent,其中有三个队列(数据结构为链表)分别存放读写时间、定时器、与信号事件,通过底层I\O复用方法检测,若事件产生就将事件挪至就绪队列中,然后将就绪队列中对应的回调函数一一执行,来相应事件

永久事件需要配合其他事件进行辅助,当我们将事件添加至队列中,当事件产生挪至就绪队列,响应后队列中该事件将不复存在,只相应一次,而永久事件在处理完后,还会再将该事件放回队列,可以将该事件继续检测而不是只检测一次

启动事件循环后,I\O函数会循环检测三个队列上有没有事件产生,若三个队列都为空则会直接退出;或者三个队列不为空,我们调用了退出事件循环的方法退出

在上面的示例中,我们并没有主动去使用事件类型,这是因为我们使用evsignal_new方法以及evtimer_new方法来实现,这两种方法实际上是对event_new方法的封装

在这里我们并没有看到我们的事件类型,现在我们将它展开,将创建信号与定时器的事件表现出来


修改后的完整代码如下,编译运行查看

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<event.h>
#include<assert.h>void signal_cb(int fd,short event,void* arg)
{if(event & EV_SIGNAL){//fd与事件类型 系统传入,其他参数在argprintf("sig = %d\n",fd);}
}
void timeout_cb(int fd,short event,void* arg)
{if(event & EV_TIMEOUT){printf("Time out\n");}
}int main()
{//实例初始化struct event_base* base = event_init();assert(base != NULL);//定义信号事件//参数://哪个实例//信号是谁//如何处理信号,回调函数//传入参数//struct event* sig_ev = evsignal_new(base,SIGINT,signal_cb,NULL);struct event* sig_ev = event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,signal_cb,NULL);assert(sig_ev != NULL);//注册//参数://添加事件//事件超时事件event_add(sig_ev,NULL);//定义定时事件//struct event* timeout_ev = evtimer_new(base,timeout_cb,NULL);struct event* timeout_ev = event_new(base,-1,EV_TIMEOUT,timeout_cb,NULL);struct timeval tv = {3,0};//指3秒0微秒event_add(timeout_ev,&tv);//启动事件循环event_base_dispatch(base);//阻塞在这里 内部进行循环 并且libevent会根据情况去选择使用select,poll,或eopll//释放事件与实例event_free(sig_ev);event_free(timeout_ev);event_base_free(base);
}


定时器不是永久事件,触发一次后就会被移除,而信号事件是永久时间则会一直触发

如果我们删除在添加信号时间时,加入的永久事件

struct event* sig_ev = event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,signal_cb,NULL);
struct event* sig_ev = event_new(base,SIGINT,EV_SIGNAL,signal_cb,NULL);


这时当程序启动,当libevent内部读写事件,定时事件以及信号事件的队列都为空时,事件循环结束,程序结束,而不像上面会不断循环去检测信号事件

使用Libevent完成tcp服务端

客户端代码

首先创建监听队列去监听读事件来自客户端的连接,然后继续监听读事件来自客户段发送来的消息

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<event.h>void recv_cb(int fd, short ev, void* arg)
{if(ev & EV_READ){char buff[128] = {0};int n = recv(fd,buff,127,0);if(n<=0){close(fd);printf("client close\n");return;}printf("buff=%s\n",buff);send(fd,"ok",2,0);}
}
void accept_cb(int fd, short ev, void* arg)
{struct event_base * base = (struct event_base*)arg;if(ev & EV_READ){struct sockaddr_in caddr;int len = sizeof(caddr);int c = accept(fd,(struct sockaddr*)&caddr,&len);if(c < 0){return;}printf("accept c = %d\n",c);struct event* c_ev = event_new(base,c,EV_READ|EV_PERSIST,recv_cb,NULL);//无法将c_ev指针传入进函数,函数返回才会产生c_evif(c_ev == NULL){close(c);return;}event_add(c_ev,NULL);}
}
int create_socket();
int main()
{int sockfd = create_socket();assert(sockfd != -1);struct event_base * base = event_init();assert(base != NULL);//监听读事件struct event * sock_ev = event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,base);assert(sock_ev != NULL);event_add(sock_ev,NULL);event_base_dispatch(base);event_free(sock_ev);event_base_free(base);exit(0);}
int create_socket()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){return -1;}res = listen(sockfd,5);if(res == -1){return -1;}return sockfd;
}

客户端代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);assert(sockfd!=-1);assert(sockfd != -1);struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res != -1);while(1){printf("input:\n");char buff[128] = {0};fgets(buff,128,stdin);if(strncmp(buff,"end", 3) == 0){break;}send(sockfd,buff,strlen(buff),0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff = %s\n",buff);}close(sockfd);
}

运行结果查看

以上代码存在一个问题

其中event_free(sock_ev)在释放过程中,不仅释放了空间同时会在libevent中移除,而在监听来自客户端发送消息的读事件,无法将其释放,因为我们并没有创建该监听事件的指针(c_ev),想要解决这个问题需要我们间接的将c_ev的指针传入进去(malloc),或者定义一个数组,根据描述符做下标,c_ev来做值实现映射关系。

Libevent库的介绍与应用相关推荐

  1. libevent库介绍

    libevent库 1.安装 https://gitee.com/craboy1/libraries/blob/master/libgevent/libgevent.c libevent库介绍 htt ...

  2. 【libevent】libevent库学习总结(一)——基础

    libevent库学习总结(一)--基础 一.基础 1.1. 介绍 Libevent是一个用于开发可伸缩网络服务器的事件通知库.Libevent API提供了一种机制来执行回调函数,当某个特定事件发生 ...

  3. Libevent库的学习

    目录 Libevent 概述 Libevent 使用模型 使用Libevent的基本流程: libevent 的核心,event 事件 1. 创建一个事件event 2. 释放event_free 3 ...

  4. C++各大有名库的介绍之C++标准库

    C++各大有名库的介绍之C++标准库 标准库中提供了C++程序的基本设施.虽然C++标准库随着C++标准折腾了许多年,直到标准的出台才正式定型,但是在标准库的实现上却很令人欣慰得看到多种实现,并且已被 ...

  5. libevent库的安装与使用

    一.libevent库的安装 Libevent 使用源码安装的方式,源码下载地址:http://libevent.org/ 下载下来后,将 Libevent 的压缩包拷贝到 Linux 系统中,然后按 ...

  6. Android之Google推荐的图片加载库Glide介绍

    原文链接:Google推荐的图片加载库Glide介绍 作者 : nuuneoi 译者 : jianghejie 校对者 :

  7. 数据分析与挖掘中常用Python库的介绍与实践案例

    数据分析与挖掘中常用Python库的介绍与实践案例 一.Python介绍 现在python一词对我们来说并不陌生,尤其是在学术圈,它的影响力远超其它任何一种编程语言, 作为一门简单易学且功能强大的编程 ...

  8. matlab图片导出无失真库export_fig介绍(半透明效果)

    matlab图片导出无失真半透明等功能的库export_fig介绍 首先,感谢export_fig的作者Yair Altman为相关方面做了很多介绍,本文主要结合新版本matlab,对作者的内容进行搬 ...

  9. C++各大有名库的介绍(一)

    C++各大有名库的介绍之C++标准库 标准库中提供了C++程序的基本设施.虽然C++标准库随着C++标准折腾了许多年,直到标准的出台才正式定型,但是在标准库的实现上却很令人欣慰得看到多种实现,并且已被 ...

最新文章

  1. Silverlight 游戏开发小技巧:轨迹跟随效果
  2. linux 搭建jenkins
  3. Java连接FTP服务器并且实现对其文件的上传和下载
  4. Android开发:5-2、ListView、GridView、Spinner
  5. 5-10多分支网络结构
  6. python中如何调用类takes no arguments_关于python中的 take no arguments 的解决方法
  7. 盘点 2017 年度最受欢迎的十大 Linux 服务器发行版
  8. 自学python要多久-大家觉得自学python多久能学会?
  9. 在导出php,PDF导出在php
  10. java插件不启动_java-插件安装后Eclipse启动问题
  11. YII之yiic创建YII应用
  12. 微博android4.1.2,微博客户端Fuubo
  13. 小牛各个版本的限速破解方式-适用N1/M1/N1s----附加转向灯提示音修改
  14. simnow账户无法使用,simnow账户修改密码
  15. 转载至:http://blog.csdn.net/antony9118/article/details/51425581
  16. SpringBoot学习:整合shiro(rememberMe记住我功能)
  17. html创建电子邮件链接教程
  18. 顺序栈的创建以及各种操作
  19. ubuntu 命令行关机
  20. 密码的修改(首先获取该用户的id,原密码判断是否一致,新密码和再次输入密码判断是否一样)...

热门文章

  1. 电脑永久删除的文件怎么恢复?这个可以帮到你
  2. unity编程实践 牧师与魔鬼
  3. zotero联合坚果云与zotfile的换机同步实录
  4. centos 开机后提示failed to initialize packaging backend
  5. STM32获取唯一身份标识unique ID
  6. div+css如何用一张背景图实现全站背景图片调用
  7. Java原理 面向对象的特征与“六原则一法则”
  8. JAVA-Ftp上传文件,文件上传上去了,但是大小是0KB
  9. mysql 无法启动14001_Mysql服务无法启动,解决办法。
  10. 让你了解INTEL发展和一些专有名词