本文转载自:https://blog.csdn.net/yuliying/article/details/42126195
使用默认配置开始事件循环: event_base_dispatch()
开始事件循环,可以设置一些参数: event_base_loop()
指定时间后退出事件循环,处理完回调函数后退出 : event_base_loopexit()
立即退出事件循环: event_base_loopbreak()
文件描述符【已经】可读/可写.
文件描述符【变为】可读/可写.(边缘触发模式下)
超时事件时间已到
进程收到信号
用户自己触发事件
已初始化状态(initialized). 设置好一个事件,并且将其关联到一个event_base.
等待状态(pending). 将上述已初始化状态的事件添加到event_base,事件变为待触发状态.
激活状态(active). 待触发事件的触发条件满足,事件变为触发状态.
EV_TIMEOUT : 超时事件.当在添加事件到循环(event_add)的时候设置一个超时时间.这个标记超时的时候在回调函数中的事件集合中被标记.
EV_READ : 文件描述符可读事件
EV_WRITE: 文件描述符可写事件
EV_SIGNAL: 进程信号事件
EV_PERSIST : 将当前事件标记为永久事件,非永久事件只能激活一次,回调函数执行后变为已始化状态.永久事件激活处理后后变为等待状态.
EV_ET : 该文件描述符事件使用边缘触发方式.
初始化事件: event_new()
添加事件到事件循环 : event_add()
从事件循环删除事件,不再监听:event_del()
销毁事件: event_free()
判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. event_pending()
设置事件的优先级: event_priority_set()
获取事件对应的文件描述符: event_get_fd()
从事件获取event_base : event_get_base()
获取关注的事件: event_get_events()
获取事件的回调函数: event_get_callback()
获取事件回调函数的参数: event_get_callback_arg()
获取事件的优先级: event_get_priority()
手动激活事件: event_active()
初始化事件: evtimer_new()
添加事件到事件循环 : evtimer_add()
从事件循环删除事件,不再监听: evtimer_del()
销毁事件: evtimer_del()
判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. evtimer_pending()
初始化事件: evsignal_new()
添加事件到事件循环 : evsignal_add()
从事件循环删除事件,不再监听: evsignal_del()
销毁事件: event_free()
判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. evsignal_pending()
#include
#include
#include
#include
#include
//保存所有fd对应的event结构体指针.方便销毁事件.
//一些事件的销毁这里就不做处理了.实际程序中注意内存泄露.当事件已经无用后记得销毁掉.
struct event * fdevent_array[10000];
void setnonblock(int fd)
{
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
void reuseAddr(int fd) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
}
void read_cb(evutil_socket_t fd, short events, void *arg)
{
struct event * myevent;
if ( events & EV_READ ){
//真正的应用中这里需要两个用户的buffer来保存该连接上的数据.
char buffer[1024];
while(1){
memset( buffer , 0 , 1024);
int nbytes = read( fd , buffer , 1023);
if ( nbytes < 0){
if (errno == EINTR) continue;
if (errno == EAGAIN) break;
printf("client error , fd [%d]\n" , fd);
goto fdclose;
break;
}
if ( nbytes == 0){
printf("client close , fd [%d]\n" , fd);
goto fdclose;
break;
}
printf("data from client: %s" , buffer);
write( fd , buffer , nbytes);
}
}
return;
fdclose:
//
myevent = fdevent_array[fd];
event_del(myevent);
event_free(myevent);
close(fd);
fdevent_array[fd] = NULL;
}
void listen_cb(evutil_socket_t listener, short events , void *arg)
{
if (events & EV_TIMEOUT ){
printf("timer event\n");
}
if (events & EV_READ ){
struct event_base *base = arg;
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
//接受了一个新客户连接,我们为这个新连接设置一个事件
if(fd > 0){
printf("accept new client fd [%d]\n" , fd);
setnonblock( fd );
//我们现在只关注读事件,将客户端发来的信息回送给客户端.
struct event * client_event = event_new( base , fd , EV_READ|EV_PERSIST , read_cb , (void*)base );
event_add( client_event , NULL);
fdevent_array[fd] = client_event;
}
}
}
void sigint_cb(evutil_socket_t sig, short events , void *arg){
struct event_base *base = arg;
if ( events & EV_SIGNAL ){
printf("capture signal [%d]\n" , sig);
event_base_loopbreak(base);
}
}
int main(){
//
struct event_base * base = event_base_new();
//以下代码开启server监听一个本地端口.可以将ip改为自己的服务器以方便测试.
int port = 9999;
struct sockaddr_in my_addr;
memset( &my_addr , 0 , sizeof(struct sockaddr_in));
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(port);
my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
int listen_socket = socket(AF_INET , SOCK_STREAM , 0);
setnonblock(listen_socket);
reuseAddr(listen_socket);
bind(listen_socket , (struct sockaddr*)&my_addr , sizeof(struct sockaddr));
listen(listen_socket , 10);
//给监听的socket添加一个事件,用来accept新连接,关注读事件,并将该event设置为永久事件.设置好回调函数和参数.
struct event *listener_event = event_new( base , listen_socket , EV_READ|EV_PERSIST , listen_cb , (void*)base);
//将监听事件加入事件循环.同时我们在监听事件上加一个定时器事件.在回调函数中判断应该接受连接还是定时器触发.
struct timeval expire = { 5 , 0 };
event_add( listener_event , &expire);
fdevent_array[listen_socket] = listener_event;
//设置一个信号事件,我们监听(ctrl+c的中断信号),收到信号后打印一条消息,退出事件循环.
struct event *signal_event = evsignal_new( base , SIGINT , sigint_cb , (void*)base);
evsignal_add( signal_event , NULL );
//开始事件循环
event_base_dispatch( base );
//
event_base_free(base);
}