Bufferevent
Bufferevents are higher level than evbuffers: each has an underlying evbuffer for reading and one for writing, and callbacks that are invoked under certain circumstances.
#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <event.h> #include <event2/listener.h> #define SVR_IP "127.0.0.1" #define SVR_PORT 10000 #define BUFF_SIZE 1024 static void read_cb(struct bufferevent *bev, void *ctx) { char buff[BUFF_SIZE]; int len; memset(buff, 0, sizeof(buff)); /* Read data */ len = bufferevent_read(bev, buff, sizeof(buff)); printf("read: len=[%d] data=[%s]\n", len, buff); /* Write data */ bufferevent_write(bev, buff, len); } static void write_cb(struct bufferevent *bev, void *ctx) { printf("write finished\n"); } static void event_cb(struct bufferevent *bev, short events, void *ctx) { if (events & BEV_EVENT_EOF) { printf("client disconnect\n"); bufferevent_free(bev); } else if (events & BEV_EVENT_TIMEOUT) { printf("client timeout\n"); bufferevent_free(bev); } else { /* Other case, maybe error occur */ bufferevent_free(bev); } } static void accept_cb(struct evconnlistener *lev, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *ctx) { struct event_base *evbase = ctx; struct bufferevent *bev; struct timeval tv; printf("client connect from [%s:%u] over fd [%d]\n", inet_ntoa(((struct sockaddr_in *) sa)->sin_addr), (unsigned short) ntohs(((struct sockaddr_in *) sa)->sin_port), fd); /* Create socket-based buffer event */ bev = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE); if (bev == NULL) { printf("bufferevent_socket_new() failed\n"); evutil_closesocket(fd); return; } /* Set up callback function */ bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL); /* Set up timeout for data read */ tv.tv_sec = 5; tv.tv_usec = 0; bufferevent_set_timeouts(bev, &tv, NULL); /* Enable read event */ bufferevent_enable(bev, EV_READ); } int main(void) { struct event_base *evbase; struct sockaddr_in sin; struct evconnlistener *lev; /* Initialize event base */ if ((evbase = event_base_new()) == NULL) { printf("event_base_new() failed\n"); return -1; } /* Set up server address */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(SVR_IP); sin.sin_port = htons(SVR_PORT); /* Bind socket */ lev = evconnlistener_new_bind(evbase, accept_cb, evbase, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr *) &sin, sizeof(sin)); if (lev == NULL) { printf("bind() failed\n"); return -1; } else { printf("bind to [%s:%u] successfully\n", SVR_IP, SVR_PORT); } /* Enter event loop */ event_base_dispatch(evbase); return 0; }
編譯 (指定library path)
gcc -g -Wall -o server server.c -levent -I/opt/libevent-2.0.10-stable/include/ -L/opt/libevent-2.0.10-stable/lib/
Libevent 2.0 supports multiple threads.
回覆刪除How would you change your code to support multiple threads? Greetings.
As I know, if you want to read/write socket cross thread, you should perform some init. funciton:
刪除evthread_use_pthreads(),
evthread_make_base_notifiable()
and create object with thread safe flag:
BEV_OPT_THREADSAFE,
LEV_OPT_THREADSAFE