Getting started with Linux libevent

#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/thread.h>

#include <arpa/inet.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

/*
libevent 重要函数
    event_base_new (类似epoll_create)  创建实例,初始化管理的代码
    event_base_dispatch  (类似epoll_wait)  
    event_new 
    event_add
    event_del
    event_free 
    evconnlistener_new_bind   把socket和事件的监听绑定


//回调函数的定义
typedef void (*evconnlistener_cb)(struct evconnlistener*,
                                    evutil_socket t,
                                    struct sockaddr*,
                                    int socklen,void*);  

struct evconnlistener*
evconnlistener_new_bind(struct event_base* base, 
                        evconnlistener_cb cb,   //回调函数
                        void* ptr,              // 回调函数的一个输入参数 (上下文)
                        unsigned flags,         // 事件的标识
                        int backlog,            //
                        const struct sockaddr* sa,    
                        int socklen);


官网  http://libevent.org/
从官网下载 libevent-2.1.12-stable.tar.gz
或者直接获取源码  wget -c addr --no-check-certificate
解压  tar -zxvf libevent-2.1.12-stable.tar.gz
 编译安装   
    ./configure --prefix=/usr/local/libevent
    make && sudo make install
    设置环境变量  vim ~/.bashrc
    写入
        unset PKG_CONFIG_LIB
        export PKG_CONFIG_PATH=/usr/local/libevent/lib/pkgconfig:$PKG_CONFIG_PATH
        export LD_LIBRARY_PATH=/usr/local/libevent/lib:$LD_LIBARRY_PATH
     保存后 执行 source ~/.bashrc   让环境变量生效

  通过命令   pkg-config --libs --cflags libevent  可以获取到 libevent 的头文件和所在库的路径
  env | grep LD  查看LD_LIBRARY_PATH  环境变量  (安装到系统目录下才有)
 
//----------------------------------------------------

bufferevent 缓冲区,可以与socket绑定
    内部由输入和输出缓冲区组成
    每个socket对应一个bufferevent
*/

// 程序编译
// g++  tcp_server.c  -o lserver `pkg-config --libs --cflags libevent`

//查看服务是否启动
//netstat -nptl | grep 8111



//读事件的回调
static void echo_read_cb(struct bufferevent *bev, void *ctx)
{
    /* 获取bufferevent中的读和写的指针 */
    /* This callback is invoked when there is data to read on bev. */
    struct evbuffer *input = bufferevent_get_input(bev);
    struct evbuffer *output = bufferevent_get_output(bev);
    /* 把读入的数据全部复制到写内存中 */
    /* Copy all the data from the input buffer to the output buffer. */
    evbuffer_add_buffer(output, input);  //系统就会从output取出数据发给客户端
}

//写事件的回调
static void echo_event_cb(struct bufferevent *bev, short events, void *ctx)
{
    if (events & BEV_EVENT_ERROR)
        perror("Error from bufferevent");
    if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
        bufferevent_free(bev);
    }
}

//回调函数
static void accept_conn_cb(struct evconnlistener *listener,evutil_socket_t fd, struct sockaddr *address, int socklen,void *ctx)
{
    /* 初始化一个bufferevent用于数据的写入和读取,首先需要从Listerner中获取event_base */
    /* We got a new connection! Set up a bufferevent for it. */
    struct event_base *base = evconnlistener_get_base(listener);
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    /*设置buferevent的回调函数,这里设置了读和事件的回调函数*/
    bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL); 
    /* 启用该bufevent写和读 */
     bufferevent_enable(bev, EV_READ|EV_WRITE);
}

static void
accept_error_cb(struct evconnlistener *listener, void *ctx)
{
    struct event_base *base = evconnlistener_get_base(listener);
    int err = EVUTIL_SOCKET_ERROR();
    fprintf(stderr, "Got an error %d (%s) on the listener. ""Shutting down.\n", err, evutil_socket_error_to_string(err));

    event_base_loopexit(base, NULL);
}

int
main(int argc, char **argv)
{
    struct event_base *base;
    struct evconnlistener *listener;
    struct sockaddr_in sin;

    int port = 8111;

    /*
    if (argc > 1) {
        port = atoi(argv[1]);
    }
    if (port<=0 || port>65535) {
        puts("Invalid port");
        return 1;
    }*/


    //use threads
    //evthread_use_pthreads();

//(1)
    base = event_base_new(); /* 初始化event_base */
    if (!base) {
        puts("Couldn't open event base");
        return 1;
    }

    /*初始化绑定地址*/
    /*Clear the sockaddr before using it, 
     * in case there are extra platform-specific fields 
     * that can mess us up.
     */
    memset(&sin, 0, sizeof(sin));
    /*This is an INET address */
    sin.sin_family = AF_INET;
    /*Listen on 0.0.0.0*/
    sin.sin_addr.s_addr = INADDR_ANY;
    /*Listen on the given port.*/
    sin.sin_port = htons(port);

//(2)
    /* 初始化evconnlistener(绑定地址、设置回调函数以及连接属性) */  
    listener = evconnlistener_new_bind(base, accept_conn_cb, NULL, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,(struct sockaddr*)&sin, sizeof(sin));
    if (!listener) {
        perror("Couldn't create listener");
        return 1;
    }

    /* 设置Listen错误回调函数 */
    evconnlistener_set_error_cb(listener, accept_error_cb);

    /* 开始accept进入循环 */
    event_base_dispatch(base);
    return 0;
}

 

Guess you like

Origin blog.csdn.net/m0_37981386/article/details/112552297