11.1 HelloWorld服务器
#include <string.h>#include <errno.h>#include <stdio.h>#include <signal.h>#ifndef WIN32#include <netinet/in.h># ifdef _XOPEN_SOURCE_EXTENDED# include <arpa/inet.h># endif#include <sys/socket.h>#endif#include <event2/bufferevent.h>#include <event2/buffer.h>#include <event2/listener.h>#include <event2/util.h>#include <event2/event.h>static const char MESSAGE[] = "Hello, World!\n";static const int PORT = 9995;static void listener_cb(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);static void conn_writecb(struct bufferevent *, void *);static void conn_eventcb(struct bufferevent *, short, void *);static void signal_cb(evutil_socket_t, short, void *);intmain(int argc, char **argv){ struct event_base *base; struct evconnlistener *listener; struct event *signal_event; struct sockaddr_in sin;#ifdef WIN32 WSADATA wsa_data; WSAStartup(0x0201, &wsa_data);#endif base = event_base_new(); if (!base) { fprintf(stderr, "Could not initialize libevent!\n"); return 1; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT); listener = evconnlistener_new_bind(base, listener_cb, (void *)base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { fprintf(stderr, "Could not create a listener!\n"); return 1; } signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); if (!signal_event || event_add(signal_event, NULL)<0) { fprintf(stderr, "Could not create/add a signal event!\n"); return 1; } event_base_dispatch(base); evconnlistener_free(listener); event_free(signal_event); event_base_free(base); printf("done\n"); return 0;}static voidlistener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data){ struct event_base *base = user_data; struct bufferevent *bev; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); if (!bev) { fprintf(stderr, "Error constructing bufferevent!"); event_base_loopbreak(base); return; } bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL); bufferevent_enable(bev, EV_WRITE); bufferevent_disable(bev, EV_READ); bufferevent_write(bev, MESSAGE, strlen(MESSAGE));}static voidconn_writecb(struct bufferevent *bev, void *user_data){ struct evbuffer *output = bufferevent_get_output(bev); if (evbuffer_get_length(output) == 0) { printf("flushed answer\n"); bufferevent_free(bev); }}static voidconn_eventcb(struct bufferevent *bev, short events, void *user_data){ if (events & BEV_EVENT_EOF) { printf("Connection closed.\n"); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s\n", strerror(errno));/*XXX win32*/ } /* None of the other events can happen here, since we haven't enabled * timeouts */ bufferevent_free(bev);}static voidsignal_cb(evutil_socket_t sig, short events, void *user_data){ struct event_base *base = user_data; struct timeval delay = { 2, 0 }; printf("Caught an interrupt signal; exiting cleanly in two seconds.\n"); event_base_loopexit(base, &delay);}
11.2 基于事件服务器
11.2.1 服务端
#include <event2/event-config.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/queue.h>#include <unistd.h>#include <sys/time.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <event.h>static voidfifo_read(evutil_socket_t fd, short event, void *arg){ char buf[255]; int len; struct event *ev = arg; /* Reschedule this event */ event_add(ev, NULL); fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n", (int)fd, event, arg); len = read(fd, buf, sizeof(buf) - 1); if (len == -1) { perror("read"); return; } else if (len == 0) { fprintf(stderr, "Connection closed\n"); return; } buf[len] = '\0'; fprintf(stdout, "Read: %s\n", buf);}intmain(int argc, char **argv){ struct event evfifo; struct stat st; const char *fifo = "event.fifo"; int socket; if (lstat(fifo, &st) == 0) { if ((st.st_mode & S_IFMT) == S_IFREG) { errno = EEXIST; perror("lstat"); exit(1); } } unlink(fifo); if (mkfifo(fifo, 0600) == -1) { perror("mkfifo"); exit(1); } /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */ socket = open(fifo, O_RDONLY | O_NONBLOCK, 0); if (socket == -1) { perror("open"); exit(1); } fprintf(stderr, "Write data to %s\n", fifo); /* Initalize the event library */ event_init(); /* Initalize one event */ event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo); /* Add it to the active events, without a timeout */ event_add(&evfifo, NULL); event_dispatch(); return (0);}
11.2.2 客户端
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <pthread.h>int main(int argc, char *argv[]){ int fd = 0; char *str = "hello libevent!"; fd = open("event.fifo", O_RDWR); if (fd < 0) { perror("open error"); exit(1); } while (1) { write(fd, str, strlen(str)); sleep(1); } close(fd); return 0;}
11.3 回显服务器
#include <event2/listener.h>#include <event2/bufferevent.h>#include <event2/buffer.h>#include <arpa/inet.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>static voidecho_read_cb(struct bufferevent *bev, void *ctx){ /* This callback is invoked when there is data to read on bev. */ struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *output = bufferevent_get_output(bev); /* Copy all the data from the input buffer to the output buffer. */ evbuffer_add_buffer(output, input);}static voidecho_event_cb(struct bufferevent *bev, short events, void *ctx){ if (events & BEV_EVENT_ERROR) perror("Error from bufferevent"); if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { bufferevent_free(bev); }}static voidaccept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx){ /* We got a new connection! Set up a bufferevent for it. */ struct event_base *base = evconnlistener_get_base(listener); struct bufferevent *bev = bufferevent_socket_new( base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL); bufferevent_enable(bev, EV_READ|EV_WRITE);}static voidaccept_error_cb(struct evconnlistener *listener, void *ctx){ struct event_base *base = evconnlistener_get_base(listener); int err = EVUTIL_SOCKET_ERROR(); fprintf(stderr, "Got an error %d (%s) on the listener. " "Shutting down.\n", err, evutil_socket_error_to_string(err)); event_base_loopexit(base, NULL);}intmain(int argc, char **argv){ struct event_base *base; struct evconnlistener *listener; struct sockaddr_in sin; int port = 9876; if (argc > 1) { port = atoi(argv[1]); } if (port<=0 || port>65535) { puts("Invalid port"); return 1; } base = event_base_new(); if (!base) { puts("Couldn't open event base"); return 1; } /* Clear the sockaddr before using it, in case there are extra * platform-specific fields that can mess us up. */ memset(&sin, 0, sizeof(sin)); /* This is an INET address */ sin.sin_family = AF_INET; /* Listen on 0.0.0.0 */ sin.sin_addr.s_addr = htonl(0); /* Listen on the given port. */ sin.sin_port = htons(port); listener = evconnlistener_new_bind(base, accept_conn_cb, NULL, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { perror("Couldn't create listener"); return 1; } evconnlistener_set_error_cb(listener, accept_error_cb); event_base_dispatch(base); return 0;}
11.4 http服务器
#include <stdio.h>#include <stdlib.h>#include <unistd.h> //for getopt, fork#include <string.h> //for strcat//for struct evkeyvalq#include <sys/queue.h>#include <event.h>//for http//#include <evhttp.h>#include <event2/http.h>#include <event2/http_struct.h>#include <event2/http_compat.h>#include <event2/util.h>#include <signal.h>#define MYHTTPD_SIGNATURE "myhttpd v 0.0.1"//处理模块void httpd_handler(struct evhttp_request *req, void *arg) { char output[2048] = "\0"; char tmp[1024]; //获取客户端请求的URI(使用evhttp_request_uri或直接req->uri) const char *uri; uri = evhttp_request_uri(req); sprintf(tmp, "uri=%s\n", uri); strcat(output, tmp); sprintf(tmp, "uri=%s\n", req->uri); strcat(output, tmp); //decoded uri char *decoded_uri; decoded_uri = evhttp_decode_uri(uri); sprintf(tmp, "decoded_uri=%s\n", decoded_uri); strcat(output, tmp); //解析URI的参数(即GET方法的参数) struct evkeyvalq params; //将URL数据封装成key-value格式,q=value1, s=value2 evhttp_parse_query(decoded_uri, ¶ms); //得到q所对应的value sprintf(tmp, "q=%s\n", evhttp_find_header(¶ms, "q")); strcat(output, tmp); //得到s所对应的value sprintf(tmp, "s=%s\n", evhttp_find_header(¶ms, "s")); strcat(output, tmp); free(decoded_uri); //获取POST方法的数据 char *post_data = (char *) EVBUFFER_DATA(req->input_buffer); sprintf(tmp, "post_data=%s\n", post_data); strcat(output, tmp); /* 具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出 ... */ /* 输出到客户端 */ //HTTP header evhttp_add_header(req->output_headers, "Server", MYHTTPD_SIGNATURE); evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8"); evhttp_add_header(req->output_headers, "Connection", "close"); //输出的内容 struct evbuffer *buf; buf = evbuffer_new(); evbuffer_add_printf(buf, "It works!\n%s\n", output); evhttp_send_reply(req, HTTP_OK, "OK", buf); evbuffer_free(buf);}void show_help() { char *help = "http://localhost:8080\n" "-l <ip_addr> interface to listen on, default is 0.0.0.0\n" "-p <num> port number to listen on, default is 1984\n" "-d run as a deamon\n" "-t <second> timeout for a http request, default is 120 seconds\n" "-h print this help and exit\n" "\n"; fprintf(stderr,"%s",help);}//当向进程发出SIGTERM/SIGHUP/SIGINT/SIGQUIT的时候,终止event的事件侦听循环void signal_handler(int sig) { switch (sig) { case SIGTERM: case SIGHUP: case SIGQUIT: case SIGINT: event_loopbreak(); //终止侦听event_dispatch()的事件侦听循环,执行之后的代码 break; }}int main(int argc, char *argv[]) { //自定义信号处理函数 signal(SIGHUP, signal_handler); signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); //默认参数 char *httpd_option_listen = "0.0.0.0"; int httpd_option_port = 8080; int httpd_option_daemon = 0; int httpd_option_timeout = 120; //in seconds //获取参数 int c; while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) { switch (c) { case 'l' : httpd_option_listen = optarg; break; case 'p' : httpd_option_port = atoi(optarg); break; case 'd' : httpd_option_daemon = 1; break; case 't' : httpd_option_timeout = atoi(optarg); break; case 'h' : default : show_help(); exit(EXIT_SUCCESS); } } //判断是否设置了-d,以daemon运行 if (httpd_option_daemon) { pid_t pid; pid = fork(); if (pid < 0) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid > 0) { //生成子进程成功,退出父进程 exit(EXIT_SUCCESS); } } /* 使用libevent创建HTTP Server */ //初始化event API event_init(); //创建一个http server struct evhttp *httpd; httpd = evhttp_start(httpd_option_listen, httpd_option_port); evhttp_set_timeout(httpd, httpd_option_timeout); //指定generic callback evhttp_set_gencb(httpd, httpd_handler, NULL); //也可以为特定的URI指定callback //evhttp_set_cb(httpd, "/", specific_handler, NULL); //循环处理events event_dispatch(); evhttp_free(httpd); return 0;}