libevent编写服务端的步骤
- 生成上下文
event_base* base = event_base_new();- 绑定服务端的地址
sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT);- 使用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));- 进入事件循环
event_base_dispatch(base);- 释放资源
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);
}
以上的客户端将源文件发送给服务端。