• 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`
  • 相关阅读:
    matplotlib实战
    matplotlib常用操作2
    matplotlib 常用操作
    pandas总结
    朴素贝叶斯算法python实现
    什么叫“回归”——“回归”名词的由来&&回归与拟合、分类的区别 && 回归分析
    Latex常用整理
    准备尝试openFrameworks
    常用工具库总结
    K-Means和K Nearest Neighbor
  • 原文地址:https://www.cnblogs.com/ssyfj/p/14837436.html
Copyright © 2020-2023  润新知