简单介绍libevent快速上手

2023-05-16

http://blog.chukong-inc.com/index.php/2012/02/26/%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8Dlibevent%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/

简介

libevent是一个事件出发的网络库,使用与 windows,linux,bad, mac os 等的高性能跨平台网络库 ,支持的多种I/O 网络模型 epoll poll dev/poll select kqueue 等

Libevent安装过程

  • Version:libevent-2.0.16
    #http://cloud.github.com/downloads/libevent/libevent/libevent-2.0.16-stable.tar.gz
    #tar -xzvf libevent-2.0.16.tar.gz
    #cd libevent-2.0.16
    #./configure -prefix=/usr/local
    #make
    #sudo make install

源代码文件组织结构

  • 头文件:
    1.libevent共用的头文件都在event2目录里                                                                                    2.正常头文件后面没有特效后缀                                                                                                      3.比如后缀“xx_struct.h”这种类型的文件里的任何结构体要是直接以来的话会破坏程序对其  他版本libevent的二进制前荣幸,有时候是以非常难以调试的方式出现
  • 内部头文件:
    1.xxx-internal.h 后最的文件内部使用的头文件                                                                                    2.目的是内部数据结构和函数,信息隐藏
  • libevent框架
    1.event.c里有对event的整体框架实现
  • 对系统I/O多路复用机制的封装
    1.epool.c  : 对epoll的封装
    2.select.c : 对select的封装
    3.devpoll.c : 对dev/poll的封装
    4.kqueue.c : 对kqueue的封装
  • 定时事件管理
    1.min-heap.h  定时器事件管理 堆结构
  • 信号事件管理
    signal.c : 对新号事件的处理
  • 补助功能函数
    evutil.h 和 evutil.c  util.h : 一些补助功能函数,包括创建socket pair 和一些时间操作函数 加,减,等
  • 缓冲区管理
    evbuffer.h  bufferevent.h 对缓冲区的封装
  • lievent 里用到的基本数据结构
    compat\sys  下的queue.h 文件对 链表,双向链表,

Libevent 库的结构

  • Libevent_core
    包含所有核心的事件和缓冲功能
    event_base,evbuffer,bufferevent,和几个附加补助功能
  • Libevent_extra
    定义了程序可能需要,也可能不需要的协议特定功能,包括HTTP、DNS和RPC
  •  Libevent
    这个库没用以后版本会删掉
  • Libevent_pthreads
    pthread可一直线程库的线程和锁定实现
  • Libevent_openssl这个库为使用bufferevent和OpenSSL进行加密的通信提供支持。注意bufferevent 目前只支持 tcp 不支持udp

 

Libevent主要功能主键

  • Evutil  : 网络补助工具
  • Event,eventbase  : Libevent核心事件和事件管理
  • Bufferevent :为libevent基于事件的核心提供使用方便的封装除了通知程序套接字(注意 : 目前只针对于tcp  udp不支持)
  • Evbuffer : 在bufferevent层之下实现了缓冲功能,并且提供了方便有效的访问函数。

Libevent普通简单例子实现

Source code    
int main( )
{
int listen_fd;
struct event ev_accept;
//--相当于创建一个事件堆 以后事件可以往这里注册了--
base = event_base_new();
listen_fd = socket( AF_INET,SOCK_STREAM,0 );
if( listen_fd <0 )
return;
int reuseaddr_on = 1;
if( setsockopt( listen_fd,SOL_SOCKET,SO_REUSEADDR,&reuseaddr_on,sizeof(reuseaddr_on) ) == -1 )
{
cout<<"Error : Setsockopt failed" <<endl;
}
//--SetSocket_listenaddr--
struct sockaddr_in listen_addr;
memset( &listen_addr,0,sizeof( listen_addr ) );
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = INADDR_ANY;
listen_addr.sin_port = htons( 80800 );
if( bind( listen_fd,(struct sockaddr*)&listen_addr,sizeof( listen_addr ) ) < 0)
{
cout<<"Error : Bind failed"<<endl;
}
if( listen( listen_fd,500 ) < 0 )
{
cout<<"Error : Listen failed"<<endl; return ;
}
if( SetNonBlock(listen_fd) < 0 )
{
cout<<"Error : SetNonBlock failed"<<endl; return;
}
//--初始化事件ev_accept 设置accept回调函数和 和事件类型--
event_set( &ev_accept,listen_fd,EV_READ|EV_PERSIST,on_accept,NULL );
//--设置完的ev_accept事件注册到 base里--
event_base_set( base,&ev_accept );
//--正事添加事件 相当于注册完的事件激活--
event_add( &ev_accept,NULL );
//--事件堆run部分--
event_base_dispatch(base);
return 1;
}

 

accpet callback code

Source code    
void on_accept(int fd,short ev,void* arg)
{
int client_fd;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof( client_addr );
client_fd = accept( fd,(struct sockaddr*)&client_addr,&client_len );
if( client_fd == -1 )
{
cout<<"Error : accept client failed"<<endl;
}
if (SetNonBlock(client_fd) < 0)
{
cout<<"Error : Set client socket nonblock"<<endl;
}
static int index = 0;
cout << "客户端 "<< index <<"-----" << inet_ntoa( client_addr.sin_addr ) <<" 已链接 ~~~~~" <<endl;
index++;
//--accept到的 新客户端 注册一个recv 事件--
stMyClient* pClient = new stMyClient();
//--使用刚连接客户端的文件描述符 监视 recv 消息--
event_set( &pClient->ev_read,client_fd,EV_READ|EV_PERSIST,on_read,pClient );
event_base_set( base,&pClient->ev_read );
event_add( &pClient->ev_read,NULL );
}

recv callback code

Source code    
void on_read( int fd,short ev,void* arg )
{
struct stMyClient* client = (stMyClient*)arg;
char buff[65535];
memset( buff,0x00,sizeof( buff ) );
int nSize = read( fd,buff,65535 );
if( nSize == 0 )
{
cout<<"Client disconnected "<<endl;
close(fd);
event_del( &client->ev_read );
delete client;
return;
}
else if( nSize < 0 )
{
cout<<"Socket failed disconnected "<<endl;
close(fd);
event_del( &client->ev_read );
delete client;
return;
}
cout<<"Read :"<<buff<<endl;
}

关于使用Bufferevent 和 多线程用法

Source code    
//--线程回调--
void* ProcessThread( void* pthread )
{
CVitNetThread* p = (CVitNetThread*)pthread;
//--p->GetEvQueue() 这里获取到的是event_base对象--
//--这里相当于把事件堆绑定在当前线程里--
event_base_dispatch(p->GetEvQueue());
return NULL;
}
void main()
{
//----listen bind 部分同上---
//
//----------------------------
m_pEvQueue = event_base_new();
event_assign( &m_incEvent, m_pEvQueue,fd, evType, accept_cb, this);
event_base_set( m_pEvQueue,&m_incEvent );
event_add( &m_incEvent,NULL );
//--注意这里event_base堆里一个事件都没注册情况下 不能创建线程--
//--因为event_base_dispatch();此函数判断没有事件注册了的就会退出线程的--
int ret;
if ((ret = pthread_create(&m_incThreadID, NULL, ProcessThread,this)) != 0)
{
s_pLog->Log(LOG_ERROR, "%s %s => CreateThread failed",__FILE__,__FUNCTION__) ;return false;
}
}
Source code    
void accept_cb( int fd,short ev,void* arg )
{
CVitNetThread *p = (CVitNetThread*)arg;
int client_fd = -1;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof( client_addr );
client_fd = accept( fd,(struct sockaddr*)&client_addr,&client_len );
if( client_fd == -1 )
{
s_pLog->Log(LOG_ERROR, "%s %s => accept client failed fd = [%d]",__FILE__,__FUNCTION__,client_fd) ;return;
}
if (evutil_make_socket_nonblocking(client_fd) < 0)
{
s_pLog->Log(LOG_ERROR, "%s %s => Set client socket nonblock is failed",__FILE__,__FUNCTION__,client_fd) ;return;
}
//--这里创建一个缓存事件 对象 设置 recv write error 回调函数--
//--这里系统要是有recv到得信息的时候会自动调用recv_cb回调函数的
//--这里系统要是有send信息的时候自动调用write_cb回调函数
//--这里系统要是有出错或延迟的时候回调用此error_cb回调函数
bufferevent* bufferev = bufferevent_new( client_fd,recv_cb,write_cb,error_cb,p );
if( bufferev == NULL )
{
s_pLog->Log(LOG_ERROR, "%s %s => bufferev bis NULL",__FILE__,__FUNCTION__) ;return;
}
//--bufferev 事件 注册到 消息堆里 event_base 这里( p->GetEvQueue()返回一个event_base对象)
bufferevent_base_set( p->GetEvQueue(),bufferev );
bufferevent_enable( bufferev, EV_READ | EV_WRITE );
}

bufferevent recv,error

Source code    
void recv_cb( struct bufferevent *ev, void *arg )
{
CVitNetThread *p = (CVitNetThread*)arg;
if( p == NULL )
{
s_pLog->Log(LOG_ERROR, "%s %s => argument is NULL",__FILE__,__FUNCTION__) ;return;
}
int fd = bufferevent_getfd(ev);
char buffer[READ_MAX]; memset( buffer, 0x00,sizeof( buffer ) );
int ret = bufferevent_read(ev, &buffer,evbuffer_get_length( ev->input ));
cout<<buffer<<endl;
}
void error_cb( struct bufferevent *ev, short events ,void *arg )
{
CVitNetThread *p = (CVitNetThread*)arg;
int fd = bufferevent_getfd(ev);
if( events & BEV_EVENT_CONNECTED )
cout<<"Connect ok"<<endl;
else if( events & (BEV_EVENT_ERROR | BEV_EVENT_EOF) )
cout<<"disconnect"<<endl;
else if( events & BEV_EVENT_TIMEOUT )
cout<<"TimeOut"<<endl;
else if( events & BEV_EVENT_WRITING )
cout<<"Wrting"<<endl;
bufferevent_free(ev);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单介绍libevent快速上手 的相关文章

  • 给力!简单!易懂!位运算之求集合的所有子集

    摘要 刚刚完成一篇利用位运算高效地 巧妙地来解决求组合的博文 xff1a 非常给力 xff1a 位运算求组合 巧合的是 xff0c 我在 数据结构算法与应用 一书中看到一道课后题是 xff1a 用递归实现求一个集合的所有子集 受到题目的要求
  • 一种复杂度为O(n)的排序算法:位操作应用之位排序

    位运算应用篇 3 摘要 本篇仍然关注位操作的应用 xff0c 通过前面的两篇文章 非常给力 xff1a 位运算求组合 xff0c 简单 易懂 xff1a 位运算之求集合的所有子集 xff0c 我们已经略见了位操作之强大威力 如果说那两篇文章
  • 求砖拍:绝对深入剖析各种方法实现两个变量的交换

    本篇摘要 交换两个变量是非常古老的话题了 xff0c 然而本文绝对保证给你新鲜的感觉 xff01 本文涉及到最简单的 不用临时变量交换两个整数 还涉及到如果利用异或来实现两个指针 两个浮点数的交换 xff0c 要知道指针的浮点数是不允许直接
  • RAID制作全程图解 实际操作很简单

    说到磁盘阵列 xff08 RAID xff0c Redundant Array of Independent Disks xff09 xff0c 现在几乎成了网管员所必须掌握的一门技术之一 xff0c 特别是中小型企业 xff0c 因为磁盘
  • LSI 1064E RAID1和RAID0的配置步骤

    一 RAID1的步骤 xff1a 开机自检过程中出现ctrl 43 c提示 xff0c 按ctrl 43 c进入LSI Logic Config Utility v6 10 02 00 xff08 2006 09 27 xff09 1 在S
  • Mac下使用homebrew安装配置mysql

    步骤 xff1a 一 安装homebrew 二 安装mysql 三 配置自启动 四 修改mysql密码 五 创建my cnf配置文件 一 安装homebrew homebrew是macOS缺失的软件包管理器 xff0c 譬如可以下载mysq
  • 本地策略不允许您使用交互式登录

    此系统的本地策略不允许您采用交互式登录解决方法 如果计算机是一台不在域中的单独的Windows 2000计算机 xff0c 参考以下步骤 xff1a 1 启动故障计算机至登录状态 xff1b 2 登录到网络中的另外一台Windows 200
  • 用ipmitool管理服务器

    service ip mi start ip mitool I open shell 可以直接进入本地BMC shell ip mitool I lan H U shell 输入password 进入IP MI交互模式 当然这里也可以把sh
  • 命令行设置raid:MegaCli一些简单用法

    查看raid级别 xff1a MegaCli LDInfo Lall aALL 查看raid卡信息 xff1a MegaCli AdpAllInfo aALL 查看硬盘信息 xff1a MegaCli PDList aALL 查看电池信息
  • Cache写机制:Write-through与Write-back

    参考http en wikipedia org wiki Cache Writing Policies上的说明 xff0c Cache写机制分为write through和write back两种 Write through Write i
  • Windows 2008 部署服务之客户端安装

    作者 xff1a 罗国荣 日期 xff1a 2010 05 27 在 Windows 2008 部署服务之Windows XP映像捕获 中我介绍了如何利用捕获映像从已使用 Sysprep exe 准备的参考计算机捕捉计算机的映像 xff0c
  • Windows 2008 部署服务之Windows 7 应答文件创建

    Windows 2008 部署服务之Windows 7 应答文件创建 作者 xff1a 罗国荣 日期 xff1a 2010 05 27 前面我们介绍了如何创建Windows XP的应答文件 xff0c 在这一章中我将给大家介绍如何使用Win
  • Windows 2008 部署服务之Windows 7 映像捕获

    作者 xff1a 罗国荣 日期 xff1a 2010 05 27 在 Windows 2008 部署服务之Windows XP映像捕获 中我介绍了如何利用捕获映像从已使用 Sysprep exe 准备的参考计算机捕捉计算机的映像 xff0c
  • 部署Vista – 第1部分:理解Windows AIK

    原创作品 xff0c 允许转载 xff0c 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 http iwantfly blog 51cto com 1048259 234142 最近在学习Windows
  • 部署Vista – 第2部分:理解Windows安装程序和Windows映像文件格式

    标签 xff1a 部署Vista WINDOWS安装程序 映像 原创作品 xff0c 允许转载 xff0c 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 http iwantfly blog 51cto
  • 部署Vista – 第3部分:理解配置传送

    标签 xff1a 部署Vista 配置传送 原创作品 xff0c 允许转载 xff0c 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 http iwantfly blog 51cto com 104825
  • 无线信号的调制方式 OOK、ASK、FSK、GFSK

    一 OOK OOK On Off Keying 通断键控 如上图所示 xff0c Vm t 是需要发送的数字信号 xff0c Acos 2 fct 是未经过调制的载波 xff0c VAM t 是经过OOK调制的载波信号 OOK的调制原理就是
  • Collections类方法详解____(一)排序操作类

    Collections类对于java集合的学习至关重要 xff0c 这里简单收录了Collections类的基本方法和详解 xff0c 下面先给出汇总列表 Collections类常用方法 分类方法用法 排序操作 sort Collecti
  • 部署Vista – 第4部分:理解部署场景

    标签 xff1a 部署Vista 部署场景 原创作品 xff0c 允许转载 xff0c 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 http iwantfly blog 51cto com 104825
  • 部署Vista – 第6部分:使用Windows SIM

    标签 xff1a 部署Vista Windows SIM 原创作品 xff0c 允许转载 xff0c 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 http iwantfly blog 51cto com

随机推荐