libevent的使用

一:libevent的编译安装

(一)下载地址

https://libevent.org/

(二)编译安装

./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`
原文地址:https://www.cnblogs.com/ssyfj/p/14837436.html