libevent 库基于事件驱动( event-driven),高性能;轻量级,专注于网络,采用Reactor设计模型。
libevent网络编程流程:
server端:所有的客户连接通过一个buffer全局数据管理,读入的消息用全局消息数据管理。
struct bufferevent* buffers[MAX_CONNECTION]; int cur_con = 0; int msgs_len = 2;
message_t* msgs;
msgs = (message_t*)malloc(sizeof(message_t)*MAX_MESSAGE_TOTAL)
main函数:
struct sockaddr_in srv; memset(&srv,0,sizeof(srv)); srv.sin_family = AF_INET; srv.sin_port = htons(10001); srv.sin_addr.s_addr = htonl(INADDR_ANY); struct event_base* base; struct evconnlistener* evlistener; base = event_base_new();
//evconnlistener_new_bind作用:socket,bind,listen并accept
evlistener = evconnlistener_new_bind(base,evlistener_cb,args,LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,16,(struct sockaddr*)&srv,sizeof(srv)); evconnlistener_set_error_cb(evlistener,evlistener_error_cb);//设置evlistener错误回调 event_base_dispatch(base); //进入事件循环
evlistener_error_cb回调:当evlistener出现错误,则调用此回调
void evlistener_error_cb(struct evconnlistener* listener,void *arg){ print_err("listen errir ,exit"); event_base_loopbreak(base); }
evlistener_cb回调:当evlistener上有连接进入,则调用此回调。bufferevent_socket_new创建一个与客户端对话的buffer,在后面的通信中,就用此buffer进行数据的读写。
void evlistener_cb(struct evconnlistener* evlistener, evutil_socket_t connect_fd, struct sockaddr* cli, int cli_len, void *arg) { struct bufferevent* buffer ; buffer = bufferevent_socket_new(base,connect_fd,BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); //创建一个buffer,与客户端通信
bufferevent_enable(buffer,EV_READ | EV_WRITE); //将buffer读写打开 bufferevent_setcb(buffer,read_cb,NULL,event_cb,arg);//设置buffer上的回调函数 }
read_cb回调:当buffer上有数据时,调用此回调。bufferevent_read函数读取buffer。bufferevent_write函数向buffer中写入数据
void read_cb(struct bufferevent* buffer,void* arg){ message_t* msgs = arg; int i = 0; while(bufferevent_read(buffer,(msgs + msgs_len),sizeof(message_t)) != 0){ if(msgs_len == MAX_MESSAGE_TOTAL - 1){ memcpy(msgs + 2,msgs+(MAX_MESSAGE_TOTAL/2 + 2),sizeof(message_t)*(MAX_MESSAGE_TOTAL/2 - 2)); msgs_len = (MAX_MESSAGE_TOTAL/2 - 1 ); } msgs_len++; printf("current message cont = %d ",msgs_len); for(i = 0; i < cur_con; i++){ deliver_msg(buffers[i],(msgs + msgs_len - 1));
//在此函数内调用bufferevent_write()函数 } } }
event_cb当buffer上有事件产生时(错误发生:eof,error),调用此回调。释放资源,并断开客户端连接
void event_cb(struct bufferevent* buffer,short event,void* arg){ int i = 0; int n = 0; if(event && BEV_EVENT_EOF){ printf("connection %d closed ",bufferevent_getfd(buffer)); }else if(event && BEV_EVENT_ERROR){ print_err("got error on thin connection"); } if(event && (BEV_EVENT_EOF | BEV_EVENT_ERROR)){ for(i = 0; i < cur_con;i++){ if(buffers[i] == buffer){ for(n = i ; n < cur_con - 1; n++){ buffers[n] = buffers[n+1]; } break; } } cur_con --; bufferevent_setcb(buffer,NULL,NULL,NULL,NULL);//关掉所有buffer上的事件 bufferevent_free(buffer); //free buffer,与客户端断开连接。 } }
client端:
main函数:创建base,创建buffer,并与服务端连接,在buffer上祖册读事件,接收用户输入,将输入写入buffer,创建独立线程去运行事件派发函数。
struct sockaddr_in srv; memset(&srv,0,sizeof(srv)); srv.sin_port = htons(10001); srv.sin_family = AF_INET; inet_pton(AF_INET,argv[1],&srv.sin_addr); struct event_base* base; base = event_base_new(); struct bufferevent* buffer; buffer = bufferevent_socket_new(base,-1,BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); bufferevent_setcb(buffer,read_cb,NULL,NULL,NULL); bufferevent_enable(buffer, EV_READ | EV_WRITE); if(pthread_create(&thread_id,NULL,(void*)ev_dispatch,NULL) != 0){ print_err("create thread failed"); } //处理客户输入 printf("