libevent动态库的编译链接
安装过程:
- 对.tar.gz包 解压安装
- 切换到源码对应的文件夹 cd/lib.... -stable
- 可能需要yum install libssl-dev
- ./configure 会生成一个Makefile文件
- make
- make install
- 注意看libevent的include lib等文件放在哪
使用gcc编译:
gcc -std=gnu99 -o libo1_test lib01_test.c -I/usr/local/include/ -L /usr/local/lib/ -levent
要-I链接include/头文件目录 ,-L 链接lib文件 libevent相关文件放在这些位置
在这些弄好后,还是会出错
需要在/usr/lib64下创建libevent的链接
ln -s /usr/local/lib/libevent-2.1.so.7 /usr/lib64/libevent-2.1.so.7 即可
为了更简便,输入命令:
export LD_LIBRARY_PATH=/usr/local/lib #具体文件路径看情况
也可以:/etc/profile 将命令加入到该文件
后面即可直接:
gcc -o bufferevent_client bufferevent_client.c -levent
ibevent的 event_base 事件处理框架
event_base结构体是一个事件的集合,在这个集合里检测那个事件被激活,然后执行事件
事件处理框架通过使用epoll poll select 检测事件
类似boost的io_content的run()
使用:
- 创建一个事件处理框架
- 创建一个事件
- 事件添加进事件处理框架
- 开始事件循环
- 释放资源
event_base结构体类似epoll句柄
#include<stdio.h>
#include<unistd.h>
#include<event2/event.h>
#include<event2/util.h>
int main(int argc,char* argv[])
{
struct event_base* base=event_base_new();//创建事件集合
const char** str=event_get_supported_methods();
for(int i=0;str[i]!=NULL;i++)
{
puts(str[i]);
} event_base_free(base); //释放event_base event_base_dispatch(base);//事件循环
return 0;
}
子进程中event_base
event_base初始化后,fork()创建子进程后,子进程复制父进程的代码资源,同样在子进程中也有struct event_base* base;但是在子进程中要初始化该base event_reinit(base);
创建事件 struct event 没有缓冲区
what主要对应上面的宏定义 事件创建默认水平模式,事件触发调用回调函数处理 void*arg作为回调函数的参数
event_new()创建的事件为非未决状态,通过加入到event_base()为未决状态
非未决:没有资格被处理 未决:有资格但还没被处理
调用事件创建函数创建事件;然后将事件加入到事件处理event_base上
所有新创建的事件都是初始化的,并且非阻塞,调用event_add可以让一个事件变为阻塞。
调用event_free释放event,在事件阻塞或者激活状态下调用event_free是安全的,这个函数会在释放event之前将事件变为非阻塞并且非激活状态。
event_del(struct event* ev);//从event_base中删除事件
当一个事件被触发,在事件对应的回调函数调用前该事件就会变为非阻塞的
事件循环
event_base_dispatch(struct event_base base);* event_base循环处理其事件集
事件在event_base上等待触发,事件被触发后调用回调函数执行,若是事件只触发一次,则被触发后,事件移出event_base。可通过在事件event_new()时,将事件的short what赋值为持续触发:EV_PERSIST
持续触发,只要触发就调用回调函数,处理后有进入event_base处理集
退出事件循环
event_base_loopexit(...base,...tv)可设定多长时间退出事件循环,若是在设定时间退出时,正在执行回调函数,则执行完在退出。
事件在循环中被触发,进入激活状态 调用回调函数,调用后事件又变为非未决状态
event结合管道读写的例子
读管道:
#include<fcntl.h>
#include<stdlib.h>
#include<event2/event.h>
#include<event2/util.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<memory.h>
//管道通信 在读写端有事件触发时回调函数处理
//回调函数,有三个参数
void read_cb(evutil_socket_t fd,short what,void* arg)//会持续读,写端关闭后还是持续读
{
char buff[1024];
memset(buff,0,sizeof(buff));
if(read(fd,buff,sizeof(buff))<0)
{
perror("read error");
exit(1);
}
printf("read:%s\n",buff);
}
int main(int argc,char* argv[])
{
unlink("myfifo");
mkfifo("myfifo",0777);//创建管道通信的管道文件
int fd=open("myfifo",O_RDONLY|O_NONBLOCK);//打开管道文件,读端
if(fd==-1)
{
perror("open error");
exit(1);
}
//已经打开管道文件,获得了读端的fd;接下来是把读端的事件加到event_base里,有读端数据触发则处理
struct event_base* base=event_base_new();
//创建读端事件 触发读事件后,调用回调函数read_cb
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);
return 0;
}
管道写端:
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<memory.h>
#include<event2/event.h>
#include<event2/util.h>
//管道通信 在写端能触发时回调函数处理
//回调函数,有三个参数
void write_cb(evutil_socket_t fd,short what,void* arg)
{
char*buff="write to fifo";
size_t size=strlen(buff);
if(write(fd,buff,size)!=size)
{
perror("read error");
exit(1);
}
}
int main(int argc,char* argv[])
{
//先打开读端,再打开写端
int fd=open("myfifo",O_WRONLY|O_NONBLOCK);//打开管道文件,写端
if(fd==-1)
{
perror("open error");
exit(1);
}
//已经打开管道文件,获得了写端的fd;接下来是把写端的事件加到event_base里,可以写触发则处理
struct event_base* base=event_base_new();
//创建写端事件 触发写事件后,调用回调函数write_cb
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);
return 0;
}
bufferevent
读缓冲区有数据,触发读事件,在读回调中使用bufferevent_read()读出,写缓冲区有数据会自动发送,触发写回调函数
bufferevent有读写缓冲区,当读缓冲区有数据时,读缓冲区对应的回调函数会被调用,在回调函数中读缓冲区数据
bufferevent_read()
当有数据要发送,调用bufferevent_write()
往写缓冲区写入数据,写缓冲区有数据,会自动发送数据,发生数据后,写回调才被调用
bufferevent主要使用在服务端与客户端进行交互通信的fd上
//释放bufferevent:void bufferevent_free(struct bufferevent* bev);
//读写缓冲区的回调函数:
typedef void (*bufferevent_data_cb) (struct bufferevent* bev,void* ctx);
typedef void (*bufferevent_event_cb) (struct bufferevent* bev,short events,void* ctx);
- 创建bufferevent事件 bufferevent_socket_new()
- bufferevent_setcb()设置读写回调函数
- 定义读写回调函数
- 在读写回调函数使用bufferevent_read() bufferevent_write()读写
buffer_socket_connect()主要用在客户端要与服务端建立连接
默认ev_write是enable
默认ev_read是关闭的,要使用ev_read先enable开启
server使用bufferevent流程:要监听,bind等(创建前缀的流程)
绑定加监听 evconnlistener_new_bind()返回监听器对象,有连接到来调用回调函数 (listen()函数)
回调函数 类似accept()函数
服务端事件示例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<event2/util.h>
#include<event2/bufferevent.h>
#include<event2/listener.h>
#include<string.h>
//使用bufferevent实现服务端
//读回调
void read_cb(struct bufferevent* bev,void* arg)
{
char buff[1024]={0};
bufferevent_read(bev,buff,sizeof(buff));
printf("接收到:%s\n",buff);
char* pt="服务端已接收到数据";
bufferevent_write(bev,pt,strlen(pt)+1);
puts("服务端已发送数据给客户端");
}
//写回调,数据发送出去写回调才会被调用
void write_cb(struct bufferevent* bev,void* arg)
{
puts("数据已发送");
}
//事件回调,主要看发生了什么事件
void event_cb(struct bufferevent* bev,short events,void* arg)
{
if(events&BEV_EVENT_EOF)
{
puts("连接断开");
}
}
//有连接则调用回调函数处理连接,服务端连接客户端后的fd在回调函数形参上
//处理连接,将连接间的通信初始化为事件
void listen_fd(struct evconnlistener*listener,evutil_socket_t fd,struct sockaddr* addr,int len,void* ptr)
{//把连接通信封装成bufferevent事件
struct event_base* base=(struct event_base*)ptr;
//连接通信事件,bufferevent事件关联服务端与客户端连接的fd;在base上
struct bufferevent* 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(int argc,char* argv[])
{
struct event_base* base=event_base_new();//事件处理框架
struct sockaddr_in serveraddr;//服务器IP和端口
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr=INADDR_ANY;
//绑定加监听接受,调用回调时就有与客户端连接的fd,有连接 则回调,第三个参数是给回调函数传参,传给回调函数的void* ptr
struct evconnlistener* listen=evconnlistener_new_bind(base,listen_fd,base,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,-1,
(struct sockaddr*)&serveraddr,sizeof(serveraddr));
event_base_dispatch(base);//循环
evconnlistener_free(listen);
event_base_free(base);//释放资源
return 0;
}
客户端,客户端通过事件event读终端数据,用bufferevent_write发送出去
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<event2/event.h>
#include<event2/bufferevent.h>
#include<string.h>
#include<arpa/inet.h>
void read_cb(struct bufferevent* bev,void* arg)
{
char buff[1024]={0};
bufferevent_read(bev,buff,sizeof(buff));
printf("recv:%s\n",buff);
}
void event_cb(struct bufferevent* bev,short events,void* arg)
{
if(events&BEV_EVENT_EOF)
{
puts("连接断开");
}else if(events&BEV_EVENT_CONNECTED)
{
puts("已经连上");
}
}
void read_terminal(int fd,short what,void* arg)
{
char buf[1024]={0};//event事件读取终端的数据
int len=read(fd,buf,sizeof(buf));
//读取到的数据通过bufferevent事件发生出去
struct bufferevent* bev=(struct bufferevent*)arg;
bufferevent_write(bev,buf,len+1);//借用bufferevent将终端数据写到客户端缓冲区
}
int main(int argc,char* argv[])
{
struct sockaddr_in serveraddr;//服务端IP和port
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);
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);
//将事件连接到服务器
bufferevent_socket_connect(bev,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
//给事件设置回调
bufferevent_setcb(bev,read_cb,NULL,event_cb,NULL);
bufferevent_enable(bev,EV_READ);
//在事件循环前,可以接收终端输入,输入为event事件,STDIN_FILENO是终端读的文件描述符,监听终端输入,触发读事件
//把与服务端通信的事件bufferevent传给event的回调函数,通过bufferevent传给服务端
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;
}
信号事件
struct event* sig=evsignal_new(base,SIGINT,sigfunc,NULL);//NULL为信号回调函数的void* arg参数
void sig_cb(evutil_socket_t fd,short event,void *arg)
{
printf("In signal event callback\r\n");
struct event_base * base = (struct event_base *)arg;
event_base_loopbreak(base);
}
struct event_base* base=event_base_new();
struct event* ev=evsignal_new(base,
(evutil_socket_t)SIGALRM,
sig_cb,
base);
evsignal_add(ev,NULL);//添加到事件处理
标签:struct,bufferevent,网络,base,事件,libevent,include,event
From: https://www.cnblogs.com/persistencejunjie/p/17463998.html