windows下用libevent 开发一个echo服务

时间:2021-05-17 00:18:28
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <iostream>
using namespace std;

#include <event2/event.h>
#include <event2/bufferevent.h>

void accept_cb(int fd, short events, void* arg);
void socket_read_cb(bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num);

int main(int argc, char** argv)
{
#ifdef WIN32
    WSADATA wsa_data;
    WSAStartup(0x0201, &wsa_data);
#endif

    int listener = tcp_server_init(9999, 10);
    if( listener == -1 )
    {
        perror(" tcp_server_init error ");
        return -1;
    }

    struct event_base* base = event_base_new();

    //添加监听客户端请求连接事件
    struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
        accept_cb, base);
    event_add(ev_listen, NULL);

    event_base_dispatch(base);
    event_base_free(base);

#ifdef WIN32
    WSACleanup();
#endif

    return 0;
}



void accept_cb(int fd, short events, void* arg)
{
    evutil_socket_t sockfd;

    struct sockaddr_in client;
    int len = sizeof(client);

    sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
    evutil_make_socket_nonblocking(sockfd);

    cout << "accept a client " << sockfd << endl;

    struct event_base* base = (event_base*)arg;

    bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);

    bufferevent_enable(bev, EV_READ | EV_PERSIST);
}



void socket_read_cb(bufferevent* bev, void* arg)
{
    char msg[4096] = {0};

    size_t len = bufferevent_read(bev, msg, sizeof(msg));

    cout << "recv the client msg: " << msg << endl;
    // msg[len] = '\r'; 
    // msg[len+1] = '\n'; 

    char reply_msg[4096] = "I have recvieced the msg: ";

    strcat(reply_msg + strlen(reply_msg), msg);
    bufferevent_write(bev, reply_msg, strlen(reply_msg));
}



void event_cb(struct bufferevent *bev, short event, void *arg)
{

    if (event & BEV_EVENT_EOF)
    {
        cout << "connection closed" << endl;
    }
    else if (event & BEV_EVENT_ERROR)
    {
        cout << "some other error" << endl;
    }

    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
}


typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
    evutil_socket_t listener;

    listener = ::socket(AF_INET, SOCK_STREAM, 0);
    if( listener == -1 )
        return -1;

    //允许多次绑定同一个地址。要用在socket和bind之间
    evutil_make_listen_socket_reuseable(listener);

    do
    {
        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = 0;
        sin.sin_port = htons(port);
        if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
            break;

        if( ::listen(listener, listen_num) < 0)
            break;

        //跨平台统一接口,将套接字设置为非阻塞状态
        evutil_make_socket_nonblocking(listener);
        return listener;
    } while (0);

    int errno_save;
    errno_save = errno;
    evutil_closesocket(listener);
    errno = errno_save;

    return -1;
}