优点:
开源。精简。跨平台(Windows,Linux,macOS,Unix)。专注于网络。
安装: 参考readme
./configure
make
sudo make install
进入sample目录。运行监测
编译使用库的.c需要加 -levent选项
特性:
基于“事件”异步通信模型。 — 回调。
libevent库框架
创建event_base
struct event_base *event_base_new(void);
struct event_base *base = event_base_new();
创建事件event
常规事件 event _new();
bufferevent bufferevent_socket_new();
将事件 添加到base上
int event_add(struct event *ev,const struct timeval *tv);
循环监听时间满足
int event_base_dispatch(struct event_base *base);
释放event_base
void event_base_free(struct event_base *base);
创建事件
struct event *ev;
struct event *event_new(struct event_base *base,evutil_socket_t fd,short what,event_callback_fn cb,void *arg);
参1 event_base_new()返回值
fd 绑定到event上的文件描述符
what 对应的事件(读,写,异常)
EV_READ|EV_WRITE 一次读|写事件
EV_PERSIST持续触发(必须结构event_base_dispatch函数使用,生效)
cb 一旦事件满足监听条件,回调的函数
typedef void(*event_callback_fn)(evutil_socket_t fd,short,void *);
arg 回调函数的参数
返回值:成功创建的event
添加事件到event_base
int event_add(struct event *ev,const struct timeval *tv);
参1:event_new的返回值。
参2:
将事件从event_base上摘下(了解)
int event_del(struct event *ev);
释放事件
int event_free(struct event *ev);
参数:event_new()的返回值
使用fifo的读写
读端
mkfifo("myfifo",0664);
int fd = open("myfifo",O_RDONLY|O_NONBLOCK);
struct event_base *base = event_base_new();
//创建event_base
struct event *ev = event_new(base,fd,EV_READ|EV_PERSIST,read_cb,NULL);
//创建事件
event_add(ev,NULL);
//事件循环
event_base_dispatch(base);
//事件循环
event_free(ev);
event_base_free(base);
close(fd);
//释放资源
void read_cb(evutil_socket_t fd,short what,void *arg)
{
char buf[1024] = {0};
int len = read(fd,buf,sizeof(buf));//将文件读到缓冲区
.....
}
写端
int fd = open("myfifo",O_WRONLY|O_NONBLOCK);
struct event_base *base = event_base_new();
//创建event_base
struct event *ev = event_new(base,fd,EV_WRITE|EV_PERSIST,write_cb,NULL);
//创建事件
event_add(ev,NULL);
//事件循环
event_base_dispatch(base);
//事件循环
event_free(ev);
event_base_free(base);
close(fd);
//释放资源
void write_cb(evutil_socket_t fd,short what,void *arg)
{
char *buf;
cin >> buf;
int len = strlen(buf);
write(fd,buf,len);//将文件读到缓冲区
.....
}
事件的未决和非未决
未决:有资格被处理,但还没被处理
非未决:没有资格被处理
bufferevent
主要用于网络通信
创建bufferevent
struct bufferevent *bufferevent_socket_new(struct event_base *base,evutil_socket_t fd,enum bufferevent_options options);
base:event_base
fd:封装到bufferevent内的文件描述符
返回值:成功创建的bufferevent事件对象。
销毁事件
void bufferevent_free(struct bufferevent *bev);
给读写缓冲区设置回调
相当于
bufferevent_socket_new(fd)和bufferevent_setcb(callback)一起完成了
event_new(…);的工作
禁用启用缓冲区
客户端
int buffer_event_connect(struct buffer_event *bev,struct sockaddr *address,int addrlen);
服务器
struct evconnlistener *evconnlister_new_bind(
struct event_base *base,
evconnlistener_cb cb,
void *ptr,
unsighed flags,int backlog,
const struct sockaddr *sa,int socklen);
base:event_base
cb:回调函数。一旦被回调说明在其内部应该与客户端完成数据读写操作。
ptr:回调函数的参数
flags:LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE
backlog:listen()2参
sa:服务器自己地址结构体
socklen:sa结构体大小
返回值:成功创建的监听器
1.创建event_base
2.创建服务器连接监听器 evconnlistener_new_bind(),设置evconnlistener_new_bind()函数中回调函数的操作,当有客户端连接成功,这个回调函数会被调用。
3.封装lister_cb()在函数内部
4.创建bufferevent事件对象
5.使用bufferevent_setcb()设置回调函数
6.设置bufferevent的读写缓冲区enable/disable
7.启动循环event_base_dispath();
8.释放连接
释放监听服务器
void evconnlistener_free(struct evconnlistener *lev);
服务器
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#define SERV_PORT 9527
//读回调
void read_cb(struct bufferevent *bev,void *arg)
{
//需要一个buf
char buf[1024] = {0};
bufferevent_read(bev,buf,sizeof(buf));
printf("recv buf : %s\n",buf);
//发送数据,向缓冲区写数据
char *pt = "已收到发送的数据";
bufferevent_write(bev,pt,strlen(pt) + 1);
printf("send...\n");
}
void write_cb(struct bufferevent *bev,void *arg)
{
printf("已发送...");//没什么用
}
void event_cb(struct bufferevent *bev,short events,void *arg)
{
if(events & BEV_EVENT_EOF)
printf ("closed...\n");
//释放bufferevent资源
bufferevent_free(bev);//这个位置最合适
}
//连接完成之后,对应的操作
void listen_cb(struct evconnlistener *listener,
evutil_socket_t fd,
struct sockaddr *addr,
int len,void *ptr)
{
//得到传进来的base
struct event_base*base = (struct event_base*)ptr;
//接受和发送数据
//将fd封装为bufferevent
struct bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
//给读写缓冲区设置回调函数
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;
serv.sin_family = AF_INET;
serv.sin_port = htons(SERV_PORT);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
//创建监听的套接字
//绑定
//监听
//等待并接受连接
struct evconnlistener* listen = NULL;
//有新连接listen_cb被调用
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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <arpa/inet.h>
#define SERV_PORT 9527
void read_cb(struct bufferevent *bev,void *arg)
{
char buf[1024] = {0};
bufferevent_read(bev,buf,sizeof(buf));
printf("recv...\nbuf:%s",buf);
}
void write_cb(struct bufferevent *bev,void *arg)
{
printf("发送成功...\n");
}
void event_cb(struct bufferevent *bev,short events,void *arg)
{
if(events & BEV_EVENT_CONNECTED){
printf("connected...\n");
return;
}
bufferevent_free(bev);
}
void read_terminal(int fd,short what,void *arg)
{
//读终端中的数据
char buf[1024] = {0};
int len = read(fd,buf,sizeof(buf));
//将数据发给server
struct bufferevent *bev = (struct buffevent *)arg;
bufferevent_write(bev,buf,strlen(buf)+1);
}
int main()
{
//创建一个事件处理框架
struct event_base *base = event_base_new();
struct sockaddr_in serv;
inet_pton(AF_INET,"192.168.56.128",&serv.sin_addr.s_addr);
serv.sin_family = AF_INET;
serv.sin_port = htons(SERV_PORT);
//连接服务器
int fd = socket(AF_INET,SOCK_STREAM,0);
//创建事件
struct bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
bufferevent_socket_connect(bev,(struct sockaddr *)&serv,sizeof(serv));
//设置回调
bufferevent_setcb(bev,read_cb,write_cb,event_cb,NULL);
//接受键盘输入
struct event *ev = event_new(base,STDIN_FILENO,EV_READ | EV_PERSIST,read_terminal,bev);
event_add(ev,NULL);
//启动事件
event_base_dispatch(base);
//释放资源
return 0;
}