libevent框架常用接口及通信测试

2 篇文章 0 订阅
1 篇文章 0 订阅

下面是libevent框架的简单测试代码,是在学习libevent的时候写的测试代码,目的是熟悉libevent的API接口和使用流程,没有涉及到数据格式或数据解析,就是单纯的收发数据并输出到终端,并且不会对原理做解释,只是单纯的使用libevent。代码都有很详细的注释,比较容易看懂。

常用接口:

struct event_base *event_base_new();  //创建一个事件处理框架
void event_base_free(struct event_base *base); //释放资源
int event_base_dispatch(struct event_base *base); //开启事件循环

struct event *event_new(structevent_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void*arg); //创建事件
常用事件标志:
EV_READ     可读的文件描述符
EV_WRITE    可写的文件描述符
EV_SIGNAL   信号检测
EV_PERSIST  持久事件

int event_add(struct event *ev,const struct timeval *tv); //将事件添加到事件处理框架中
int event_del(struct event *ev);  //删除事件
void event_free(struct event *event);  //释放资源

struct bufferevent *bufferevent_socket_new(
struct event_base *base, evutil_socket_t fd, enum bufferevent_options options);  //创建带缓冲区的事件
注:options参数选择:
BEV_OPT_CLOSE_ON_FREE:当bufferevent释放时,关闭底层传输
BEV_OPT_THREADSAFE: 为bufferevent使用lock
BEV_OPT_DEFER_CALLBACKS: 将callback设为延迟的
BEV_OPT_UNLOCK_CALLBACKS:默认情况下如果有THREADSAFE标志,调用callback时会加锁。使用这个标志是的即便有THREADSAFE标志,调用callback也不加锁   

connect()函数的封装
int bufferevent_socket_connect (struct bufferevent *bev,
                                struct sockaddr    *address,
                                int                 addrlen);

设置回调函数
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg);

void bufferevent_enable(struct bufferevent *bufev, short events);  //设置回调函数权限可用
void bufferevent_disable(struct bufferevent *bufev, short events);
void bufferevent_free(struct bufferevent *bev); //释放资源

读写缓冲区数据
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);

**

服务端

**

#include <string.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
using namespace std;

//读回调
void read_cb(struct bufferevent *bev, void *arg){
    //读缓冲区中的数据
    char buf[1024] = {0};
    bufferevent_read(bev, buf, sizeof(buf));
    cout << "收到: " << buf;

    char pt[] = "我是read_cb, 你发送的数据我收到了!";
    //往缓冲区写数据
    bufferevent_write(bev, pt, strlen(pt) + 1);
    cout << "我是read_cb, 我往缓冲区写数据了!" << endl;
}

//写回调
void write_cb(struct bufferevent *bev, void *arg){
    cout << "我是write_cb,数据已经发送了" << endl << endl;
}

//事件回调
void event_cb(struct bufferevent *bev, short events, void *arg){
    if(events & BEV_EVENT_EOF){
        cout << "连接关闭" << endl;
    }
    else if(events & BEV_EVENT_ERROR){
        cout << "其他错误" << endl;
    }
    //释放资源
    bufferevent_free(bev);
}

void listen_cb(struct evconnlistener *listener,
               evutil_socket_t fd,
               struct sockaddr *addr,
               int len, void *ptr)
{
    //得到传进来的event_base
    struct event_base* base = (struct event_base*)ptr;
    
    //先接受数据 - 发送数据
    //将fd封装为bufferevent
    struct bufferevent* bev = NULL;
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    
    //给bufferevent对于的读写缓冲区设置回调函数
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    
    //设置读缓冲区的回调函数可用, 默认写是可用的
    bufferevent_enable(bev, EV_READ);
}

int main(){
    struct event_base* base = event_base_new(); //创建事件处理框架

    //初始化
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8765);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    /*
     evconnlistener_new_bind函数的功能有下面三个 
     1.创建套接字
     2.绑定
     3.开监听
    */
    //参数分别为: base,回调函数(自己写),回调函数传参,flags,backlog,服务端信息,socklen 
    struct evconnlistener* listen = evconnlistener_new_bind(base, listen_cb, base, 
                                                            LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                                            -1, (struct sockaddr*)&serv, sizeof(serv));

    //开启事件循环
    event_base_dispatch(base);

    //释放资源
    evconnlistener_free(listen);
    event_base_free(base);

    return 0;
}

**

客户端:

**

#include <string.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
using namespace std;

//读回调
void read_cb(struct bufferevent* bev, void* arg){
    //接收数据
    char buf[1024] = {0};
    bufferevent_read(bev, buf, sizeof(buf));
    cout << "我是read_cb, 我读到: " << buf;
    cout << "数据已经发送完成!" << endl << endl;
}

//写回调
void write_cb(struct bufferevent* bev, void* arg){
    cout << "我是write_cb, 我已经写完数据了" << endl;
}

void event_cb(struct bufferevent* bev, short events, void* arg){
    if(events & BEV_EVENT_EOF){
        cout << "连接关闭!" << endl;
    }
    else if(events & BEV_EVENT_ERROR){
        cout << "其他错误!" << endl; 
    }
    else if(events & BEV_EVENT_CONNECTED){
        cout << "连接服务器成功!" << endl;
        return;
    }
    bufferevent_free(bev);
    return;
}

void read_terminal(int fd, short what, void* arg){
    // 读终端的数据
    char buf[1024] = {0};
    int len = read(fd, buf, sizeof(buf));
    
    struct bufferevent* bev = (struct bufferevent*)arg;
    // 将数据发送给服务器
    bufferevent_write(bev, buf, len + 1);
}
int main(){
    //创建一个事件处理框架
    struct event_base* base = event_base_new();

    //创建事件
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    struct bufferevent* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    //连接服务器
    sockaddr_in serv = {0};
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8765);
    inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));
    //给缓冲区设置回调函数
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    bufferevent_enable(bev, EV_READ);

    // 往终端输入数据,然后发送到缓冲区给服务器读
    // 创建一个终端输入的新事件
    struct event* ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, 
                                 read_terminal, bev);
    event_add(ev, NULL); //添加新事件到事件处理框架
  
    //启动事件循环
    event_base_dispatch(base);

    //释放资源
    event_base_free(base);
    
    return 0;
}

**

Makefile

**

all:server.out client.out

server.out:server.cpp
		g++ server.cpp -g -o server.o -levent

client.out:client.cpp
		g++ client.cpp -g -o client.o -levent

clean:
	rm -rf server.o
	rm -rf client.o

执行结果
在这里插入图片描述

总结

libevent提供了一系列接口,其底层原理是epoll,可以支持并发,大致使用流程为:
在这里插入图片描述
需要注意的一点是,只要使用bufferevent_socket_new( )去创建事件,要给缓冲区设置回调函数,作为bufferevent_setcb( )的参数(上面代码有体现)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值