2013年2月17日星期日

简单介绍libevent快速上手


简介
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普通简单例子实现

 
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



 
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 和 多线程用法



 
//--线程回调--
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);
}

没有评论:

发表评论