/* 版本:2.1.11 源码位置:sample/hello-world.c This example program provides a trivial server program that listens for TCP connections on port 9995. When they arrive, it writes a short message to each client connection, and closes each connection once it is flushed. 这个例子提供一个小的服务器程序:监听9995端口上的TCP连接。 当连接请求到来,回写一个字符串,当写缓冲区刷新后立即断开。 Where possible, it exits cleanly in response to a SIGINT (ctrl-c). ctrl+c发送SIGINT信号后,程序响应信号并结束。 */ #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! "; 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 *); int main(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 //1.创建event_base,用于对未决事件和激活事件的监视 base = event_base_new(); if (!base) { fprintf(stderr, "Could not initialize libevent! "); return 1; } //2.服务器地址 memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT); //3.创建监听器 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! "); return 1; } //4.创建信号事件 signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); //5.将信号事件添加到调度循环 if (!signal_event || event_add(signal_event, NULL)<0) { fprintf(stderr, "Could not create/add a signal event! "); return 1; } //6.开启调度循环,监视未决事件 event_base_dispatch(base); //7.释放资源 evconnlistener_free(listener); event_free(signal_event); event_base_free(base); printf("done "); return 0; } static void listener_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 void conn_writecb(struct bufferevent *bev, void *user_data) { struct evbuffer *output = bufferevent_get_output(bev); if (evbuffer_get_length(output) == 0) { printf("flushed answer "); bufferevent_free(bev); } } static void conn_eventcb(struct bufferevent *bev, short events, void *user_data) { if (events & BEV_EVENT_EOF) { printf("Connection closed. "); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s ", strerror(errno));/*XXX win32*/ } /* None of the other events can happen here, since we haven't enabled * timeouts */ bufferevent_free(bev); } static void signal_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. "); event_base_loopexit(base, &delay); }