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
    评论
下面是一个简单的libevent TCP客户端收发数据的示例代码: ```c #include <event2/event.h> #include <event2/buffer.h> #include <event2/bufferevent.h> #include <iostream> #include <string.h> using namespace std; void read_cb(bufferevent* bev, void* arg) { char buf[1024]; size_t len = bufferevent_read(bev, buf, sizeof(buf)); buf[len] = '\0'; cout << "Received message: " << buf << endl; } void write_cb(bufferevent* bev, void* arg) { cout << "Message sent!" << endl; } void event_cb(bufferevent* bev, short events, void* arg) { if (events & BEV_EVENT_CONNECTED) { cout << "Connected to server!" << endl; bufferevent_write(bev, "Hello, server!\n", strlen("Hello, server!\n")); } else if (events & BEV_EVENT_ERROR) { cout << "Error: " << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()) << endl; event_base_loopbreak(bufferevent_get_base(bev)); } } int main(int argc, char** argv) { struct event_base* base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL); bufferevent_enable(bev, EV_READ|EV_WRITE); bufferevent_socket_connect_hostname(bev, NULL, AF_UNSPEC, "localhost", 12345); event_base_dispatch(base); bufferevent_free(bev); event_base_free(base); return 0; } ``` 在这个示例中,我们创建了一个libevent的事件循环`base`和一个TCP客户端`bev`。我们通过`bufferevent_socket_new()`函数创建了一个`bufferevent`对象,它封装了一个TCP连接。我们使用`bufferevent_setcb()`函数设置了当`bev`有读、写和事件发生时的回调函数。然后使用`bufferevent_enable()`函数启用读、写事件。接着使用`bufferevent_socket_connect_hostname()`函数连接到服务器。 当连接成功建立时,会触发`event_cb()`函数中的`BEV_EVENT_CONNECTED`事件,我们可以在这里发送一条消息给服务器,例如"Hello, server!\n"。当服务器回复消息时,会触发`read_cb()`函数,我们可以在这里读取服务器发送的消息。当发生错误时,会触发`event_cb()`函数中的`BEV_EVENT_ERROR`事件,我们可以在这里输出错误信息并停止事件循环。 需要注意的是,我们在程序结束时需要手动释放`bev`和`base`对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

顾文繁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值