libevent的使用
一:libevent的编译安装
(一)下载地址
(二)编译安装
./configure --prefix=/usr/local/libevent
sudo make && sudo make install
二:libevent基础知识学习
(一)重要函数
struct event_base *event_base_new(void); 功能:函数会检测环境变量,返回一个event_base的指针,分配并且返回一个新的具有默认设置的 event_base。类似epoll使用中的epoll_create(用于创建epoll实例),这里用于创建libevent实例,还初始化libevent管理相关的代码,比如队列创建
int event_base_dispatch(struct event_base *);
功能:事件触发,一旦创建好事件根基event_base,并且在根基上安插好事件之后,需要对事件循环监控(换句话说就是等待事件的到来,触发事件的回调函数)
(二)事件处理相关(底层)
(三)事件处理相关(高层)
evconnlistener_new_bind方法:
第一个参数代表主事件,也就是创建的event_base;
第二个参数代表回调函数,触发可读事件之后,返回给我们需要的信息
第三个参数代表需要额外传递给回调函数的参数
第四个参数代表标志位,比如:
LEV_OPT_REUSEABLE设置地址复用,內部函数原型应该是setsocketopt(sockfd, SOL_SOCKET, SO_RESUEADDR, on, sizeof(on))
LEV_OPT_CLOSE_ON_FREE代表连接开闭時同事开关底层套接字
第五个参数代表监听的最大数量(毫秒级别),如果设置为-1系统将选择一个合适的数值,如果為-1,內部实现的数值为128(固定的)跟SOMAXCONN一样的值
第六个参数代表需要綁定的地址
第七个参数代表地址的大小
函数內部创建了一個listenfd,根据你的參数是否设置为非阻塞(evutil_make_socket_nonblocking())函数进行设置,这个函数的內部为fcntl函数(flags=fcntl(fd, F_GETFL), flags |= O_NONBLOCK, fcntl(fd, F_SETFL, flags))进行设置,然后进行地址绑定(bind()),再创建一個evconnlistener *类型的对象,用evconnlistener_new()函数來进行创建,evconnlistener_new()函数內部进行监听(listen()),创建一个evconnlistener_event的監聽事件,將主事件,listenfd,回调函数,evconnlistener_event进行綁定。這個回调函数為listener_read_cb函数,當着個函数被调用的時候,內部进行accept一個connfd,进而调用我们自己的回调函数read/write等操作。
(四)缓冲区数据结构
1.bufferevent_socket_new:使用bufferevent_socket_new创建一个struct bufferevent *bev,关联该sockfd,托管给event_base
struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options)
2.bufferevent_enable:启用读写事件,其实是调用了event_add将相应读写事件加入事件监听队列poll
int bufferevent_enable(struct bufferevent *bufev, short event)
3.bufferevent_setcb回调函数:
void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb,bufferevent_event_cb eventcb,
void *cbarg);
在readcb里面从input中读取数据,处理完毕后填充到output中;
writecb对于服务端程序,只需要readcb就可以了,可以置为NULL;
errorcb用于处理一些错误信息
4.evbuffer_add_buffer:从一个evbuffer
向另一个evbuffer
移动数据
函数evbuffer_add_buffer()将src中的所有数据移动到dst末尾,成功时返回0,失败时返回-1。
evbuffer_add_buffer(output,input); //把输入的数据,添加到输出队列中去。当写事件触发后,就会去输出缓冲区中读取数据发送给系统底层
三: 使用libevent实现高性能服务器
#include <iostream> #include <event2/listener.h> #include <event2/buffer.h> #include <event2/bufferevent.h> #include <arpa/inet.h> #define PORT 8080 void on_read_cb(struct bufferevent* bev,void* ctx) { struct evbuffer *input=NULL; struct evbuffer *output=NULL; input = bufferevent_get_input(bev); output = bufferevent_get_output(bev); evbuffer_add_buffer(output,input); //把输入的数据,添加到输出队列中去。当写事件触发后,就会去输出缓冲区中读取数据发送给系统底层 } void on_accept_cb(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* addr, int socklen, void* ctx) { struct event_base *base = NULL; struct bufferevent *bev = NULL; base = evconnlistener_get_base(listener); bev = bufferevent_socket_new(base,fd,0); //使用bufferevent_socket_new创建一个structbufferevent *bev,关联该sockfd,托管给event_base bufferevent_enable(bev,EV_READ | EV_WRITE); bufferevent_setcb(bev,on_read_cb,NULL,NULL,NULL); } int main(int argc,char* argv[]) { struct sockaddr_in serveraddr; struct event_base *base = NULL; struct evconnlistener *listener = NULL; base = event_base_new(); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(PORT); serveraddr.sin_addr.s_addr = INADDR_ANY; listener = evconnlistener_new_bind(base, on_accept_cb, NULL, LEV_OPT_REUSEABLE, 10, (struct sockaddr*)&serveraddr, sizeof(serveraddr)); event_base_dispatch(base); return 0; }
编译:
g++ -g libevent_ln.cpp -o ll `pkg-config --libs --cflags libevent`