ent_set_timeouts(bev, struct timeval *READ, struct timeval *WRITE)设置读写超时, 处理error_cb中的超时。 *. read_cb和write_cb的原型是 void read_or_write_callback(struct bufferevent *bev, void *arg) error_cb的原型是 void error_cb(struct bufferevent *bev, short error, void *arg) ///这是event的标准回调函数原型 event__可以从bev中提取libevent的APIbase、sockfd、inputRTFM~/output等相关数据 所以代码简化到read_cb和read_cb,只需要几行error_cb函数即可:
void read_cb( struct bufferevent *bev, void *arg) { char line[256]; int n; evutil_socket_t fd = bufferevent_getfd(bev); while (n = bufferevent_read(bev, line, 256), n > 0) bufferevent_write(bev, line, n); } void error_cb( struct bufferevent *bev, short event, void *arg) { bufferevent_free(bev); }
因此,echo支持大并发量 server成型了!下面附上无注释的echo server源码,110行,再抄几遍,就能完全理解!更复杂的例子见官方文档中的例子【Example: A simpler ROT13 server with Libevent】
include <stdio.h> # include <stdlib.h> # include <errno.h> # include <assert.h> # include <event2/event.h> # include <event2/bufferevent.h> # define LISTEN_PORT 9999 # define LISTEN_BACKLOG 32 void do_accept(evutil_socket_t listener, short event, void *arg); void read_cb( struct bufferevent *bev, void *arg); void error_cb( struct bufferevent *bev, short event, void *arg); void write_cb( struct bufferevent *bev, void *arg); int main( int argc, char *argv[]) { int ret; evutil_socket_t listener; listener = socket(AF_INET, SOCK_STREAM, 0); assert(listener > 0); evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(LISTEN_PORT); if (bind(listener, ( struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); return 1; } if (listen(listener, LISTEN_BACKLOG) < 0) { perror("listen"); return 1; } printf ("Listening...\n"); evutil_make_socket_nonblocking(listener); struct event_base *base = event_base_new(); assert(base != NULL); struct event *listen_event; listen_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, ( void*)base); event_add(listen_event, NULL); event_base_dispatch(base); printf("The End."); return 0; } void do_accept(evutil_socket_t listener, short event, void *arg) { struct event_base *base = ( struct event_base *)arg; evutil_socket_t fd; struct sockaddr_in sin; socklen_t slen; fd = accept(listener, ( struct sockaddr *)&sin, &slen); if (fd < 0) { perror("accept"); return; } if (fd > FD_SETSIZE) { perror("fd > FD_SETSIZE\n"); return; } printf("ACCEPT: fd = %u\n", fd); struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, read_cb, NULL, error_cb, arg); bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST); } void read_cb( struct bufferevent *bev, void *arg) { # define MAX_LINE 256 char line[MAX_LINE+1]; int n; evutil_socket_t fd = bufferevent_getfd(bev); while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) { line[n] = '\0'; printf("fd=%u, read line: %s\n", fd, line); bufferevent_write(bev, line, n); } } void write_cb( struct bufferevent *bev, void *arg) {} void error_cb( struct bufferevent *bev, short event, void *arg) { evutil_socket_t fd = bufferevent_getfd(bev); printf("fd = %u, ", fd); if (event & BEV_EVENT_TIMEOUT) { printf("Timed out\n"); // if bufferevent_set_timeouts() called } else if (event & BEV_EVENT_EOF) { printf("connection closed\n"); } else if (event & BEV_EVENT_ERROR) { printf("some other error\n"); } bufferevent_free(bev); }