libevent服务端客户端

libevent编写服务端的步骤

  1. 生成上下文 
    event_base* base = event_base_new();
  2. 绑定服务端的地址
    sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
  3. 使用libevent提供的监听器listener
    evconnlistener* ev = evconnlistener_new_bind(base,
                                                 listen_cb,  // 回调函数
                                                 base,  //回调函数的参数
                                                 LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
                                                 10,  // listen back
                                                 (sockaddr*)&sin,
                                                 sizeof(sin));
  4. 进入事件循环
    event_base_dispatch(base);
  5. 释放资源
    evconnlistener_free(ev);
    event_base_free(base);

 以上是5大步骤,

再继续编写监听回调函数listen_cb

void listen_cb(evconnlistener* ev, evutil_socket_t s, sockaddr* sin, int slen, void* arg){

    event_base* base = (event_base*) arg;

    //创建bufferevent 上下文,BEV_OPT_CLOSE_ON_FREE 清理bufferevent时关闭socket
    bufferevent* bev = bufferevent_socket_new(base,s,BEV_OPT_CLOSE_ON_FREE);

    //添加监控事件
    bufferevent_enable(bev, EV_READ|EV_WRITE);

    //设置水位
    //读取水位
    bufferevent_setwatermark(bev,
                             EV_READ,
                             5,//低水位,0为无限制,默认为0
                             0);//高水位,0为无限制
    //写水位
    bufferevent_setwatermark(bev,
                             EV_WRITE,
                             5,//低水位,0为无限制,默认为0
                             0);//高水位,0为无限制
    //设置超时时间
    timeval t = {1, 0};
    bufferevent_set_timeouts(bev, &t, 0);

    //设置回调函数
    bufferevent_setcb(bev,read_cb, write_cb, event_cb,base);


}

再设置读事件、写事件、事件回调函数

客户端和服务端通信的例子

服务端

#include <iostream>
#include <event2/event.h>
#include <signal.h>
#include <thread>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <event2/listener.h>
#include <event2/thread.h>
#include <event2/bufferevent.h>
#include <string.h>

#define PORT 9988

using namespace std;

static string recvstr;
static int recvCnt = 0;
static int sendCnt = 0;

void read_cb(bufferevent* be,void* arg){
    cout << "[R]" << flush;
    char data[1024] = {0};
    //读取输入缓冲区
    size_t len = bufferevent_read(be, data, sizeof(data)-1);
    if(len <= 0) return;
    recvstr += data;
    recvCnt += len;
    //发送数据,写入输出缓冲
    bufferevent_write(be, "ok\n",3);
}

void write_cb(bufferevent* be,void* arg){
    cout << "[W]" << flush;
}

//错误,超时,连接断开会触发
void event_cb(bufferevent* be,short events, void* arg){
    cout << "[E]" << endl;
    //超时时间发生后,数据读取停止
    if(BEV_EVENT_TIMEOUT & events && BEV_EVENT_READING & events){
        cout << "BEV_EVENT_READING BEV_EVENT_TIMEOUT\n" << endl;
        char data[1024] = {0};
        //读取输入缓冲区
        size_t len = bufferevent_read(be, data, sizeof(data)-1);
        recvCnt += len;
        recvstr += data;
        bufferevent_free(be);
        //重新设置可读
        //bufferevent_enable(be, EV_READ);
        //cout << recvstr << flush;
        cout << "recv:" << recvCnt << endl;


    }else if(BEV_EVENT_ERROR & events){
        bufferevent_free(be);
    }
}



void listen_cb(evconnlistener* ev, evutil_socket_t s, sockaddr* sin, int slen, void* arg){

    event_base* base = (event_base*) arg;

    //创建bufferevent 上下文,BEV_OPT_CLOSE_ON_FREE 清理bufferevent时关闭socket
    bufferevent* bev = bufferevent_socket_new(base,s,BEV_OPT_CLOSE_ON_FREE);

    //添加监控事件
    bufferevent_enable(bev, EV_READ|EV_WRITE);



    //设置水位
    //读取水位
    bufferevent_setwatermark(bev,
                             EV_READ,
                             5,//低水位,0为无限制,默认为0
                             0);//高水位,0为无限制
    //写水位
    bufferevent_setwatermark(bev,
                             EV_WRITE,
                             5,//低水位,0为无限制,默认为0
                             0);//高水位,0为无限制
    //设置超时时间
    timeval t = {1, 0};
    bufferevent_set_timeouts(bev, &t, 0);

    //设置回调函数
    bufferevent_setcb(bev,read_cb, write_cb, event_cb,base);


}


int main(int argc, char* argv[]){

	event_base* base = event_base_new();
    //忽略管道信号,,发送数据给已经关闭的socket
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
        return 1;
    }

    sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);

    evconnlistener* ev = evconnlistener_new_bind(base,
                                                 listen_cb,  // 回调函数
                                                 base,  //回调函数的参数
                                                 LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
                                                 10,  // listen back
                                                 (sockaddr*)&sin,
                                                 sizeof(sin));

	//进入事件主循环
    event_base_dispatch(base);
    evconnlistener_free(ev);
    event_base_free(base);
}

客户端

//
// Created by wenfan on 2021/4/6.
//
#include <iostream>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <cstring>
#include <event2/listener.h>
#include <string>

#define PORT 9988

using namespace std;

static int sendCnt = 0;

//客户端
void client_read_cb(bufferevent *be, void *arg) {
    cout << "[client_R]:" << flush;
    char data[1024] = {0};
    //读取输入缓冲区
    size_t len = bufferevent_read(be, data, sizeof(data) - 1);
    cout << data << endl;
    if (len <= 0) return;
}

void client_write_cb(bufferevent *be, void *arg) {
    cout << "[client_W]" << endl;
    FILE *fp = (FILE *) arg;
    char data[1024] = {0};

    size_t len = fread(data, 1, sizeof(data) - 1, fp);
    if (len <= 0) {
        //读到结尾或者文件出错
        fclose(fp);
        //立刻清理,可能会造成缓冲数据没有发送结束
        //bufferevent_free(be);
        bufferevent_disable(be, EV_WRITE);
        return;
    }
    cout << "write:" << endl;
    cout << data << endl;
    sendCnt += len;
    bufferevent_write(be, data, len);
}

//错误,超时,连接断开会触发
void client_event_cb(bufferevent *be, short events, void *arg) {
    cout << "[client_E]" << flush;
    //超时时间发生后,数据读取停止
    if (BEV_EVENT_TIMEOUT & events && BEV_EVENT_READING & events) {
        cout << "BEV_EVENT_READING BEV_EVENT_TIMEOUT" << endl;
        //重新设置可读
        //bufferevent_enable(be, EV_READ);
        bufferevent_free(be);
        return;
    } else if (BEV_EVENT_ERROR & events) {
        cout << "BEV_EVENT_ERROR" << endl;
        bufferevent_free(be);
        return;
    }

    if (BEV_EVENT_CONNECTED & events ) {
        cout << "BEV_EVENT_CONNECTED" << endl;
        //触发write
        bufferevent_trigger(be, EV_WRITE, 0);
    }

    if(BEV_EVENT_EOF & events){
        cout << "send:" << sendCnt << endl;
        bufferevent_free(be);
    }

}


int main(int argc, char *argv[]) {

    event_base *base = event_base_new();
    //忽略管道信号,,发送数据给已经关闭的socket
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
        return 1;
    }

    bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    evutil_inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr.s_addr);

    FILE *fp = fopen(
            "/Users/***/Documents/cppProjects/learn-libevent/libevent_course/test_buf_client/buf_server.cpp",
            "rb");

    //设置回调函数
    bufferevent_setcb(bev, client_read_cb, client_write_cb, client_event_cb, fp);
    bufferevent_enable(bev, EV_READ|EV_WRITE);
    //connect
    int ret = bufferevent_socket_connect(bev, (sockaddr *) &sin, sizeof sin);
    if (ret == 0) {
        cout << "connected" << endl;
    }else if(ret == -1){
        cout << "failed to connect" << endl;
    }

    //进入事件主循环
    event_base_dispatch(base);
    event_base_free(base);
}

以上的客户端将源文件发送给服务端。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾文繁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值