bufferevent_filter_new
对缓冲区数据的过滤器
struct bufferevent *
bufferevent_filter_new(struct bufferevent *underlying,
bufferevent_filter_cb input_filter,
bufferevent_filter_cb output_filter,
int options,
void (*free_context)(void *),
void *ctx);
- 缓冲区对象上下文
- 输入缓冲区过滤回调函数
- 输出缓冲区过滤回调函数
- flag
- 回调函数
- 过滤回调函数的参数
能够对收发的数据做业务上的处理,比如压缩,加密等。加密解密是通过内存性能换取网络带宽的节约,实现了业务的解耦
减少对缓冲区的复制,类似于sendfile
零拷贝接口。
evbuffer_peek
底层是个链表从缓冲区读取数据,因为具体到读多少数据需要用户自己决定,或者由函数内部自动链起来缓冲。
直接读取缓冲数据不复制,然后经过业务处理后,再从缓冲区抽掉该部分数据对应的大小,就像水位一样,抽掉水池的水。
zlib
对于网络传输数据的压缩,因为TCP是流式的,每次连接接收到的字节数都难以确定边界,每个数据包又会不同,所以zlib
提供了适合网络传输的相关函数
deflateInit(z_stream* ,int level)
z_stream
结构体用于提供交互的,存储了空间大小,剩余大小等level
压缩等级Z_DEFAULT_COMPRESSION
Z_BEST_COMPRESSION
Z_BEST_SPEED
returns
Z_OK
Z_SYNC_FLUSH
刷新输出缓冲区,字节边界对齐
int deflate(z_stream* strm,int flush)
uInt avail_in
源空间Bytef *next_in
输入空间地址uInt avail_out
输出空间大小,处理后就是剩余空间大小Bytef *next_out
输出空间地址
shared_ptr<FILE> myFileList(fp,&fclose);
// 初始化zlib上下文
shared_ptr<z_stream> z_output (new z_stream());
deflateInit(z_output.get(),Z_DEFAULT_COMPRESSION); // 选择默认的压缩方式
z_output->avail_in = v_in[0].iov_len; // 输入数据的大小
z_output->next_in =(Byte*) v_in[0].iov_base; // 输入数据的地址
// 申请输出空间大小
evbuffer_iovec v_out[1];
evbuffer_reserve_space(dst,1024,v_out,1);
// zlib的输出空间大小
z_output->avail_out = v_out[0].iov_len;
// zlib的输出空间大小
z_output->next_out =(Byte*) v_out[0].iov_len;
evbuffer_add(dst,str.c_str(),str.size());
master.hpp
master.cpp
#ifndef __MASTER_HPP__
#define __MASTER_HPP__
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "filter.hpp"
#define PORT 5002
using namespace std;
class Cwork
{
public:
Cwork()
{
memset(&m_sin,0,sizeof(m_sin));
m_sin.sin_family = AF_INET;
m_sin.sin_port = htons(PORT);
}
~Cwork()
{
event_base_free(m_base);
evconnlistener_free(m_ev);
}
void init();
void run();
static void listen_cb(struct evconnlistener *m_ev, evutil_socket_t fd, struct sockaddr * serv_sock, int socklen, void *arg);
private:
event_base* m_base;
sockaddr_in m_sin;
evconnlistener* m_ev;
};
class event_cb
{
public:
static void sread_cb(bufferevent *be,void *arg);
static void swrite_cb(bufferevent *be,void *arg);
static void events_cb(bufferevent *be,short events,void *arg); // 参数2 需要区分事件类型
};
#endif
#include "master.hpp"
void Cwork::listen_cb(struct evconnlistener *m_ev, evutil_socket_t fd, struct sockaddr * serv_sock, int socklen, void *arg)
{
cout<<"listen "<<endl;
event_base* base = (event_base*)arg;
bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
bufferevent_enable(bev,EV_READ|EV_WRITE);
bufferevent *bev_filter = bufferevent_filter_new(bev,
Filter::fileter_in,
Filter::fileter_out,
BEV_OPT_CLOSE_ON_FREE,
0,
0);
// 注册过滤器
bufferevent_setcb(bev_filter,event_cb::sread_cb,event_cb::swrite_cb,event_cb::events_cb,NULL);
bufferevent_enable(bev_filter,EV_READ|EV_WRITE); // 开启读写权限
}
void Cwork::init()
{
m_base = event_base_new();
// 创建上下文
m_ev = evconnlistener_new_bind(m_base,
Cwork::listen_cb, //回调函数
m_base, //回调函数的参数arg
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
10, //listen back
(sockaddr*)&m_sin,
sizeof(m_sin)
);
}
void Cwork::run()
{
event_base_dispatch(m_base);
}
void event_cb::sread_cb(bufferevent *be,void *arg)
{
char data[1024] = {0};
//读取输入缓冲数据
int len = bufferevent_read(be,data,sizeof(data)-1);
cout<<"["<<data<<"]"<<endl;
if(len<=0)return;
if(strstr(data,"quit") !=NULL)
{
cout<<"quit";
//退出并关闭socket BEV_OPT_CLOSE_ON_FREE
bufferevent_free(be);
}
//发送数据 写入到输出缓冲
bufferevent_write(be,"OK\n",5);
}
void event_cb::swrite_cb(bufferevent *be,void *arg)
{
cout<<"[W]"<<endl;
}
void event_cb::events_cb(bufferevent *be,short events,void *arg)
{
if(events & BEV_EVENT_TIMEOUT)
{
cout<<"timeout"<<endl;
bufferevent_enable(be,EV_READ|EV_WRITE); // 超时可以重新将其纳入事件监听,如果可以,那就设置如果一个连接超时了三次
// bufferevent_free(be);
}
else if(events & BEV_EVENT_ERROR)
{
cout<<"close()"<<endl;
bufferevent_free(be); // 设置了关闭
}
cout<<"[E]"<<flush;
}
filter.cpp
filter.hpp
#ifndef __FILTER_HPP__
#define __FILTER_HPP__
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
using namespace std;
class Filter
{
public:
static bufferevent_filter_result fileter_out(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,enum bufferevent_flush_mode mode, void *ctx);
static bufferevent_filter_result fileter_in(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,enum bufferevent_flush_mode mode, void *ctx);
};
#endif
#include "filter.hpp"
bufferevent_filter_result Filter::fileter_out(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,enum bufferevent_flush_mode mode, void *ctx)
{
cout<<"filter_out"<<endl;
char data[1024] = {0};
//读取并清理原数据
int len = evbuffer_remove(src,data,sizeof(data)-1);
string str = "";
str += "================\n";
str += data;
str += "================\n";
evbuffer_add(dst,str.c_str(),str.size());
return BEV_OK;
}
bufferevent_filter_result Filter::fileter_in(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,enum bufferevent_flush_mode mode, void *ctx)
{
cout<<"filter_in"<<endl;
char data[1024] = {0};
//读取并清理原数据
int len = evbuffer_remove(src,data,sizeof(data)-1);
//所有字母转成大写
for (int i = 0; i < len; ++i)
{
data[i] = toupper(data[i]);
}
evbuffer_add(dst,data,len);
return BEV_OK;
}
main.cpp
#include "master.hpp"
int main(int argc,char *argv[])
{
//忽略管道信号,发送数据给已关闭的socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
//进入事件主循环
Cwork *cwork = new Cwork();
cwork->init();
cwork->run();
delete cwork;
return 0;
}