• Windows下libevent C++封装类实现


    题记

    windows平台下对于服务器高并发的网络模型选型中,使用libevent是个不错的选择。 
    本文的背景基于:国内博客对于libevent大多介绍linux实现,大多是c语言的实现,Windows平台下C++相对较少或者较旧。 
    本文针对libevent从服务端、客户端两个角度实现了封装类,真正做到,我们在使用封装类时候,只需要关注业务逻辑的处理,不需要关注socket的通信的细节。

    1. Libevent介绍

    [维基百科]libevent是一个异步事件处理软件函式库,以BSD许可证发布。libevent提供了一组应用程序编程接口(API),让程序员可以设定某些事件发生时所执行的回调函数,也就是说,libevent可以用来取代网络服务器所使用的事件循环检查框架。由于可以省去对网络的处理,且拥有不错的效能,有些软件使用libevent作为网络底层的函式库,如:memcached、Tor。

    [libevent官网介绍] 
    libevent API提供了一种机制,用于在文件描述符上发生特定事件或达到超时后执行回调函数。此外,libevent还支持基于信号或常规超时的回调。 
    libevent旨在替换在事件驱动的网络服务器中的事件循环机制。应用程序只需要调用event_dispatch()接口,然后动态添加或删除事件,而不必更改事件循环。 
    目前,libevent支持 /dev/poll, kqueue, event ports, POSIX select, Windows select(), poll 和 epoll。 其内在的事件机制是完全独立于外在的事件API ,并且libevent的简单更新可以提供新的功能,而无需重新设计应用程序。因此: 
    1)Libevent允许便携式应用程序开发,并提供操作系统上可用的最可扩展的事件通知机制。 
    2)Libevent也可以用于多线程应用程序,通过隔离每个event_base,以便只有一个线程访问它,或通过锁定访问单个共享的event_base。 Libevent可以在Linux,* BSD,Mac OS X,Solaris,Windows等上编译。 
    3)Libevent还为缓冲网络IO提供了复杂的框架,支持套接字,过滤器,速率限制,SSL,零拷贝文件传输和IOCP。 
    4)Libevent包括对几个有用的协议的支持,包括DNS,HTTP和最小的RPC框架。

    以下关于阻塞、非阻塞,同步、异步,大牛陈硕的经典回复。 
    在处理 IO 的时候,阻塞和非阻塞都是同步 IO。 
    只有使用了特殊的 API 才是异步 IO。 
    这里写图片描述

    2.为什么要使用封装好的网络库?

    [陈硕]网络编程是什么?是熟练使用Sockets API吗?说实话,在实际项目里我只用过两次Sockets API,其他时候都是使用封装好的网络库。 
    使用封装好的网络库如libevent, muduo网络库 目的之一就是想让日常的网络编程从Sockets API的琐碎细节中解脱出来,让程序员专注于业务逻辑,把时间用在刀刃上。 程序员的主要工作是在事件处理函数中实现业务逻辑,而不是和Sockets API较劲。 
    陈硕认为网络编程也可以分为三个层次: 
    1). 读过教程和文档 
    2). 熟悉本系统TCP/IP协议栈的脾气 
    3). 自己写过一个简单的TCP/IP stack

    陈硕认为TCP网络编程有三个例子最值得学习研究,分别是echo、chat、proxy,都是长连接协议。 
    Echo的作用:熟悉服务端被动接受新连接、收发数据、被动处理连接断开。每个连接是独立服务的,连接之间没有关联。在消息内容方面Echo有一些变种:比如做成一问一答的方式,收到的请求和发送响应的内容不一样,这时候要考虑打包与拆包格式的设计,进一步还可以写简单的HTTP服务。

    3.Libevent通信核心

    服务端核心步骤简化如下:

    步骤1:设置sockfd为nonblocking;

    步骤2:使用bufferevent_socket_new创建一个struct bufferevent *bev,关联该sockfd,托管给event_base;

    步骤3:使用bufferevent_setcb(bev, read_cb, write_cb, error_cb, (void *)arg)将EV_READ/EV_WRITE对应的函数;

    步骤4:使用bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST)来启动read/write事件;

    其中,在read_cb里面从input读取数据,处理完毕后塞到output中,会自动写入到sockfd; 
    在write_cb里面(对于一个echo server来说,read_cb足够了) 
    在error_cb里面处理遇到的错误。使用bufferevent_set_timeout(bev, struct timeval *READ, struct timeval *WRITE)来设置读写超时,在error_cb里面也可以处理超时。 
    可以使用bev中libevent的API提取出event_base,sockfd,input/output等相关数据。 
    客户端的操作步骤详见代码,提炼即可。

    4.C++封装的libevent Echo类

    分为:服务端YuLibeventServer类和客户端YuLibeventClient类。

    //服务端核心代码如下参考地址:

    #include "YuLibeventServer.h"
    /*
    **@author: laoyang360
    **@date: 20161211
    **@brief: The server of SimLibeventClient
    */
    
    static int s_iBlockSize = 10;
    #define MAX_LINE 1024
    YuLibeventServer *YuLibeventServer::pThis = NULL;
    
    YuLibeventServer::YuLibeventServer()
    {
    pThis = this; //将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
    m_pBase = NULL;
    m_pListener = NULL;
    m_pEvstop = NULL;
    
    }
    
    YuLibeventServer::~YuLibeventServer()
    {
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: evutil_socket_t fd
    **@brief: 设置非阻塞,禁止Nagle算法。
    */
    void YuLibeventServer::set_tcp_no_delay(evutil_socket_t fd)
    {
    int iOne = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&iOne, sizeof iOne);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: evutil_socket_t fd
    **@brief: 等待接受客户端连接处理accept、一个新客户端连接上服务器了
    */
    void YuLibeventServer::accept_conn_cb(evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sock, int socklen, void *arg)
    {
    printf("We got a new connection! Set up a bufferevent for it. accept a client %d
    ", fd);
    
    event_base *base = evconnlistener_get_base(listener);
    
    //为这个客户端分配一个bufferevent
    bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    
    set_tcp_no_delay(fd);
    
    bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);
    bufferevent_enable(bev, EV_READ | EV_WRITE);
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: bufferevent *bev, void *arg
    **@brief: echo_read_cb回调接口
    */
    void YuLibeventServer::echo_read_cb(bufferevent *bev, void *arg)
    {
    
    char msg[MAX_LINE + 1] = {0};
    int iLen = 0;
    evutil_socket_t fd = bufferevent_getfd(bev);
    while (iLen = bufferevent_read(bev, msg, sizeof(msg)-1 ), iLen > 0)
    {
    msg[iLen] = '';
    printf("fd=%u, read len = %d	 read msg: %s
    ", fd, iLen, msg);
    int iRst = bufferevent_write(bev, msg, iLen);
    if (-1 == iRst)
    {
    printf("[socket_write_cb]:error occur!
    ");
    }
    }
    
    /*
    char reply[] = "[server: i'm server, send 1111]";
    printf("writecb: len = %d
    ", 1 + strlen(reply));
    int iRst = bufferevent_write(bev, reply, 1 + strlen(reply));
    if (-1 == iRst)
    {
    printf("[socket_write_cb]:error occur!
    ");
    }
    */
    /*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);
    /*把input buffer中的所有数据 拷贝到 output buffer*/
    //evbuffer_add_buffer(output, input);
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: bufferevent *bev, void *arg
    **@brief: socket_write_cb回调接口,暂时未使用
    */
    void YuLibeventServer::socket_write_cb(bufferevent *bev, void *arg)
    {
    /*
    char reply[] = "[server: i'm server, send 1111]";
    printf("writecb: len = %d
    ", 1 + strlen(reply));
    int iRst = bufferevent_write(bev, reply, 1 + strlen(reply));
    if (-1 == iRst)
    {
    printf("[socket_write_cb]:error occur!
    ");
    }
    */
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: bufferevent *bev, short events, void *arg
    **@brief: echo_event_cb事件处理或异常处理
    */
    void YuLibeventServer::echo_event_cb(bufferevent *bev, short events, void *arg)
    {
    struct evbuffer *output = bufferevent_get_output(bev);
    size_t remain = evbuffer_get_length(output);
    
    if (events & BEV_EVENT_TIMEOUT)
    {
    printf("Timed out
    "); //if bufferevent_set_timeouts() called.
    }
    else if (events & BEV_EVENT_EOF)
    {
    printf("connection closed, remain %d
    ", remain);
    }
    else if (events & BEV_EVENT_ERROR)
    {
    printf("some other error, remain %d
    ", remain);
    }
    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: bufferevent *bev, short events, void *arg
    **@brief: signal_cb停止信号处理
    */
    void YuLibeventServer::signal_cb(evutil_socket_t sig, short events, void *arg)
    {
    struct event_base *base = (event_base *)arg;
    printf("exception: interrupt, stop now!
    ");
    
    event_base_loopexit(base, NULL);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: int port, 传入端口。
    **@brief: libevent,socket初始化等
    */
    void YuLibeventServer::init(int port)
    {
    WSADATA wsaData;
    DWORD Ret;
    if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
    printf("WSAStartup failed with error %d
    ", Ret);
    exit(1);
    }
    
    m_pBase = event_base_new();
    if (NULL == m_pBase)
    {
    printf("couldn't open event base!
    ");
    exit(1);
    }
    
    m_pEvstop = evsignal_new(m_pBase, SIGINT, signal_cb, m_pBase);
    evsignal_add(m_pEvstop, NULL);
    
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    
    m_pListener = evconnlistener_new_bind(m_pBase, accept_conn_cb, NULL,
    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
    -1, (struct sockaddr*)&sin,
    sizeof(struct sockaddr_in));
    
    if (NULL == m_pListener)
    {
    printf("couldn't create listener!
    ");
    exit(1);
    }
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: 无
    **@brief: 启动,循环执行
    */
    void YuLibeventServer::start()
    {
    event_base_dispatch(m_pBase);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: 无
    **@brief: 停止
    */
    void YuLibeventServer::stop()
    {
    if (NULL != m_pListener)
    {
    evconnlistener_free(m_pListener);
    }
    if (NULL != m_pEvstop)
    {
    event_free(m_pEvstop);
    }
    if (NULL != m_pBase)
    {
    event_base_free(m_pBase);
    }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235

    //客户端核心代码参考地址:

    #include "yuLibEventClient.h"
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@brief: The client of SimLibeventClient
    */
    
    YuLibeventClient *YuLibeventClient::pThis = NULL;
    const static char* s_serverIpAddr = "127.0.0.1";
    const static int s_iBlockSize = 10;
    const static long s_iTimeOut = 10; //超时时间
    const static int s_iSessionCnt = 10;
    int YuLibeventClient::m_siLtotal_bytes_read = 0;
    int YuLibeventClient::m_siLtotal_messages_read = 0;
    
    YuLibeventClient::YuLibeventClient()
    {
    pThis = this; //将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
    m_pBase = NULL;
    m_pListener = NULL;
    m_pszMsg = NULL;
    m_evtimeout = NULL;
    m_bevs = NULL;
    }
    
    YuLibeventClient::~YuLibeventClient()
    {
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: evutil_socket_t fd
    **@brief: 设置非阻塞,禁止Nagle算法。
    */
    void YuLibeventClient::set_tcp_no_delay(evutil_socket_t fd)
    {
    int iOne = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&iOne, sizeof iOne);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: evutil_socket_t fd, short events, void *arg
    **@brief: 超时回调函数。
    */
    void YuLibeventClient::timeoutcb(evutil_socket_t fd, short events, void *arg)
    {
    struct event_base *base = (event_base*)arg;
    printf("timeout...
    ");
    
    event_base_loopexit(base, NULL);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: int fd, short events, void* arg
    **@brief: 暂时未使用
    */
    void YuLibeventClient::cmd_msg_cb(int fd, short events, void* arg)
    {
    printf("server_msg_cb ing....
    ");
    struct bufferevent* bev = (struct bufferevent*)arg;
    
    char msg[1024] = "testlaoyang20161210";
    int iLen = 1 + strlen(msg);
    /*int iLen = bufferevent_read(bev, msg, sizeof(msg));
    if (0 == iLen)
    {
    printf("recv message empty.
    ");
    exit(1);
    }*/
    
    //把终端的消息发送给服务器端
    bufferevent_write(bev, msg, iLen);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: struct bufferevent* bev, void* arg
    **@brief: writecb回调函数,暂时未使用
    */
    void YuLibeventClient::writecb(struct bufferevent* bev, void* arg)
    {
    /*
    printf("send_server_cb running....
    ");
    
    char szSendMsg[1024] = "[writecb: i'am client]";
    int iLen = 1 + strlen(szSendMsg);
    printf("iLen = %d
    ", iLen);
    //把终端的消息发送给服务器端
    bufferevent_write(bev, szSendMsg, iLen);
    */
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: struct bufferevent* bev, void* arg
    **@brief: readcb回调函数,接收处理回调接口。
    */
    void YuLibeventClient::readcb(struct bufferevent* bev, void* arg)
    {
    char szRecvMsg[1024] = {0};
    int len = bufferevent_read(bev, szRecvMsg, sizeof(szRecvMsg));
    szRecvMsg[len] = '';
    printf("recv from server: cnt = %d, len = %d, msg = %s
    ", m_siLtotal_messages_read, len, szRecvMsg);
    
    ++m_siLtotal_messages_read;
    m_siLtotal_bytes_read += len;
    
    //把终端的消息发送给服务器端
    bufferevent_write(bev, szRecvMsg, len);
    
    //以下是chenshuo的使用方法
    /*This callback is invoked when there is data to read on bev @by chenshuo below */
    //struct evbuffer *input = bufferevent_get_input(bev);
    //struct evbuffer *output = bufferevent_get_output(bev);
    //++m_siLtotal_messages_read;
    //m_siLtotal_bytes_read += evbuffer_get_length(input);
    //evbuffer_add_buffer(output, input);
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: struct bufferevent *bev, short event, void *arg
    **@brief: eventcb回调函数,事件或出错处理回调接口。
    */
    void YuLibeventClient::eventcb(struct bufferevent *bev, short event, void *arg)
    {
    
    if (event & BEV_EVENT_EOF)
    {
    printf("connection closed
    ");
    }
    else if (event & BEV_EVENT_ERROR)
    {
    printf("some other error
    ");
    }
    else if( event & BEV_EVENT_CONNECTED)
    {
    printf("the client has connected to server
    ");
    evutil_socket_t fd = bufferevent_getfd(bev);
    set_tcp_no_delay(fd);
    }
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: int iPort, 传入端口。
    **@brief: libevent,socket初始化等
    */
    void YuLibeventClient::init(int iPort)
    {
    WSADATA wsaData;
    DWORD Ret;
    if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
    printf("WSAStartup failed with error %d
    ", Ret);
    exit(1);
    }
    
    m_timeout.tv_sec = s_iTimeOut; //60s超时
    m_timeout.tv_usec = 0;
    
    m_pszMsg = (char*)malloc(1 + s_iBlockSize);
    memset(m_pszMsg, 0, s_iBlockSize);
    for (int i = 0; i < s_iBlockSize; ++i)
    {
    m_pszMsg[i] = 't'; /*i%128;*/
    }
    m_pszMsg[s_iBlockSize] = '';
    //printf("m_pszMsg = %s
    ", m_pszMsg);
    
    m_pBase = event_base_new();
    if (!m_pBase)
    {
    printf("Couldn't open event base!
    ");
    exit(1);
    }
    
    //设定超时
    m_evtimeout = evtimer_new(m_pBase, timeoutcb, m_pBase);
    evtimer_add(m_evtimeout, &m_timeout);
    
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(iPort);
    server_addr.sin_addr.s_addr = inet_addr(s_serverIpAddr);
    
    m_bevs = (bufferevent**)malloc(s_iSessionCnt * sizeof(struct bufferevent *));
    for (int i=0; i < s_iSessionCnt; ++i)
    {
    struct bufferevent* bev = bufferevent_socket_new(m_pBase, -1, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, readcb, NULL, eventcb, NULL);
    bufferevent_enable(bev, EV_READ | EV_WRITE);
    
    evbuffer_add(bufferevent_get_output(bev), m_pszMsg, s_iBlockSize);
    
    if (bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr,
    sizeof(server_addr)) < 0)
    {
    printf("Error starting connection!
    ");
    bufferevent_free(bev);
    exit(1);
    }
    m_bevs[i] = bev;
    }
    
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: 无
    **@brief: 启动,循环执行
    */
    void YuLibeventClient::start()
    {
    event_base_dispatch(m_pBase);
    }
    
    /*
    **@author: laoyang360
    **@date: 20161211
    **@param: 无
    **@brief: 停止,内存等释放&结果统计
    */
    void YuLibeventClient::stop()
    {
    //evconnlistener_free(m_pListener);
    if (NULL != m_pBase)
    {
    event_base_free(m_pBase);
    }
    
    for (int i = 0; i < s_iSessionCnt; ++i)
    {
    if (NULL != m_bevs[i])
    {
    bufferevent_free(m_bevs[i]);
    }
    }
    
    if (NULL != m_bevs)
    {
    free(m_bevs);
    }
    
    if (NULL != m_pszMsg)
    {
    free(m_pszMsg);
    }
    
    printf("%d total bytes read
    ", m_siLtotal_bytes_read);
    printf("%d total messages read
    ", m_siLtotal_messages_read);
    printf("%.3f average messages size read
    ", (double)m_siLtotal_bytes_read/m_siLtotal_messages_read);
    printf("%.3f MiB/s throughtput
    ", (double)m_siLtotal_bytes_read/(m_timeout.tv_sec * 1024 * 1024));
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269

    4.测试效果如下

    这里写图片描述

    5.源码包下载

    http://download.csdn.net/detail/wojiushiwo987/9708418

    后记: 
    项目中用到了libevent,但我自己一直没有总结这块,从去年开始到现在这个想法持续了一年,总算了了心愿。 
    代码对大牛陈硕的C的测试代码进行了C++的封装、测试、验证。向大牛的钻研精神和毅力学习和致敬!

    参考: 
    http://blog.csdn.net/solstice/article/details/6527585 
    https://github.com/chenshuo/recipes/tree/master/pingpong/libevent 
    http://blog.csdn.net/funkri/article/details/9352955 
    http://blog.csdn.net/laoyang360/article/details/8675922

    2016年12月11日 22:16 思于宾馆

    作者:铭毅天下 
    转载请标明出处,原文地址: 
    http://blog.csdn.net/laoyang360/article/details/53576132 
    如果感觉本文对您有帮助,请点击‘顶’支持一下,您的支持是我坚持写作最大的动力,谢谢!

    http://blog.csdn.net/laoyang360/article/details/53576132

  • 相关阅读:
    html5 标签
    开发中常见问题
    This Android SDK requires Andriod Developer Toolkit version 23.0.0 or above
    onActivityResult 要加判断
    expandlistview child 不可点击
    自定义dialog布局
    mediaPlayer 播放
    转载 收藏 listview判断是否在底部
    mediaPlayer
    org.apache.http.legacy.jar 兼容
  • 原文地址:https://www.cnblogs.com/findumars/p/6384840.html
Copyright © 2020-2023  润新知