libevent2 简单服务器客户端实现

libevent2 简单服务器客户端实现
基本功能,应该比较容易扩展
windows版本,我用的vc编译,linux去掉wsa相关内容,将sprintf_s替换成snprintf应该就可以了。

server.cpp

/*
    socket server
*/

#include <iostream>

#include <signal.h>
#define WIN32
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"libevent_core.lib")
#pragma comment(lib,"libevent_extras.lib")

using std::cout;
using std::cerr;
using std::endl;

void p_evconnlistener_cb(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);
void p_bufferevent_read_cb(bufferevent* pBufferEvent, void* pUserData);
void p_bufferevent_write_cb(bufferevent* pBufferEvent, void* pUserData);
void p_bufferevent_event_cb(bufferevent* pBufferEvent, short what, void* pUserData);
void p_sigint_cb(evutil_socket_t fd, short what, void* pUserData);

int main()
{
    cout << "server start" << endl;

    // windows网络初始化
    WSAData wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    // 初始化eventbase
    event_base* pEventBase = event_base_new();
    if (pEventBase == NULL)
    {
        cerr << "event_base fail" << endl;
        return 1;
    }

    // 定制监听地址端口
    sockaddr_in server_addr;
    size_t server_addr_len = sizeof(sockaddr_in);
    memset(&server_addr, 0, server_addr_len);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(ADDR_ANY);
    server_addr.sin_port = htons(7777);

    // 代替bind&listen方法的方法……
    evconnlistener* pEvConnListener = evconnlistener_new_bind(pEventBase,
        p_evconnlistener_cb,
        pEventBase,
        LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
        -1,
        (sockaddr*)&server_addr,
        server_addr_len);

    // 监听<C-c>中断信号
    event* pSigintEvent = evsignal_new(pEventBase, SIGINT, p_sigint_cb, pEventBase);
    if ((!pSigintEvent) || (event_add(pSigintEvent, NULL) < 0))
    {
        cerr << "sigint event fail." << endl;
        return 1;
    }

    // 循环处理消息
    event_base_dispatch(pEventBase);

    // 清理
    evconnlistener_free(pEvConnListener);
    event_free(pSigintEvent);
    event_base_free(pEventBase);

    // windows网络停止
    WSACleanup();

    cout << "server stop" << endl;

    return 0;
}

// 连接回调
void p_evconnlistener_cb(evconnlistener* pEvConnListener, evutil_socket_t fd, sockaddr* addr, int socklen, void* userData)
{
    event_base* pEventBase = (event_base*)userData;

    // 绑定连接的socket和bufferevent(这里的socket默认就是非阻塞的)
    bufferevent* pBufferEvent = bufferevent_socket_new(pEventBase, fd, BEV_OPT_CLOSE_ON_FREE);
    if (!pBufferEvent)
    {
        cerr << "bufferevent fail." << endl;
        event_base_loopbreak(pEventBase);
        return;
    }

    // 添加监听socket,设置回调
    bufferevent_setcb(pBufferEvent, p_bufferevent_read_cb, p_bufferevent_write_cb, p_bufferevent_event_cb, NULL);
    // 设置处理(监听?)内容:读、写
    bufferevent_enable(pBufferEvent, EV_READ | EV_WRITE);
}

// 数据读取回调
void p_bufferevent_read_cb(bufferevent* pBufferEvent, void* pUserData)
{
    // 读数据
    char info[255];
    size_t infoLen = bufferevent_read(pBufferEvent, info, sizeof(info));
    if (infoLen < sizeof(info))
        info[infoLen] = 0;
    cout << "recv info:" << info << endl;

    // 返回数据
    char info_ret[255];
    sprintf_s(info_ret, sizeof(info_ret), "server ret:%s", info);
    bufferevent_write(pBufferEvent, info_ret, strlen(info_ret));
}

// 写数据回调
void p_bufferevent_write_cb(bufferevent* pBufferEvent, void* pUserData)
{
    cout << "react client complete." << endl;
}

// 事件处理(出错、socket中断)
void p_bufferevent_event_cb(bufferevent* pBufferEvent, short what, void* pUserData)
{
    if (what & BEV_EVENT_READING)
        cout << "event_cb BEV_EVENT_READING." << endl;
    if (what & BEV_EVENT_WRITING)
        cout << "event_cb BEV_EVENT_WRITING." << endl;
    if (what & BEV_EVENT_EOF)
        cout << "event_cb BEV_EVENT_EOF." << endl;
    if (what & BEV_EVENT_ERROR)
        cout << "event_cb BEV_EVENT_ERROR." << endl;
    if (what & BEV_EVENT_TIMEOUT)
        cout << "event_cb BEV_EVENT_TIMEOUT." << endl;
    if (what & BEV_EVENT_CONNECTED)
        cout << "event_cb BEV_EVENT_CONNECTED." << endl;

    bufferevent_free(pBufferEvent);
}

// <C-c>中断信号处理
void p_sigint_cb(evutil_socket_t fd, short what, void* pUserData)
{
    event_base* pEventBase = (event_base*)pUserData;
    timeval delay = { 2, 0 };

    cout << "stop service in 2 seconds." << endl;

    event_base_loopexit(pEventBase, &delay);
}

client.cpp

/*
    libevent临时测试客户端
*/

#include <iostream>
#include <WinSock2.h>

#pragma comment(lib,"ws2_32.lib")

using std::cout;
using std::endl;

int main()
{
    WSAData wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(7777);
    size_t addrLen = sizeof(addr);

    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET)
    {
        cout << "create sock error." << WSAGetLastError() << endl;
        return 0;
    }

    if (connect(sock, (const sockaddr*)&addr, addrLen) == SOCKET_ERROR)
    {
        cout << "connect error." << WSAGetLastError() << endl;
        closesocket(sock);
        return 0;
    }

    char info[255];
    for (int i = 0; i < 10; ++i)
    {
        sprintf_s(info, sizeof(info), "client msg:%d", i);
        send(sock, info, strlen(info), 0);

        memset(info, 0, sizeof(info));
        int infoLen = recv(sock, info, sizeof(info), 0);
        if (infoLen == 0)
        {
            cout << "sock closed." << endl;
            closesocket(sock);
            sock = NULL;
            break;
        }
        else if (infoLen < 0)
        {
            cout << "recv error." << WSAGetLastError() << endl;
            closesocket(sock);
            sock = NULL;
            break;
        }
        else
        {
            cout << "recv info:" << info << endl;
        }
    }

    if (sock)
    {
        closesocket(sock);
        sock = NULL;
    }


    WSACleanup();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值