1/* 2 This example program provides a trivial server program that listens for TCP 3 connections on port 9995. When they arrive, it writes a short message to 4 each client connection, and closes each connection once it is flushed. 5 6 Where possible, it exits cleanly in response to a SIGINT (ctrl-c). 7 */ 8 9 10 #include <string.h> 11 #include <errno.h> 12 #include <stdio.h> 13 #include <signal.h> 14 #ifndef _WIN32 15 #include <netinet/in.h> 16 # ifdef _XOPEN_SOURCE_EXTENDED 17 # include <arpa/inet.h> 18 # endif 19 #include <sys/socket.h> 20 #endif 21 //使用libevent库的头文件 22 #include <event2/bufferevent.h> 23 #include <event2/buffer.h> 24 #include <event2/listener.h> 25 #include <event2/util.h> 26 #include <event2/event.h> 27 28 static const char MESSAGE[] = "Hello, World!\n"; 29 30 static const int PORT = 9995; 31 //一些回调函数的声明,包括监听回调、写回调、事件回调、信号回调 32 static void listener_cb(struct evconnlistener *, evutil_socket_t, 33 struct sockaddr *, int socklen, void *); 34 static void conn_writecb(struct bufferevent *, void *); 35 static void conn_eventcb(struct bufferevent *, short, void *); 36 static void signal_cb(evutil_socket_t, short, void *); 37 38 39 int main(int argc, char **argv) 40 { //事件基座的变量声明 41 struct event_base *base; 42 struct evconnlistener *listener;//监听器变量声明 43 struct event *signal_event;//信号事件声明 44 45 struct sockaddr_in sin;//服务器的地址声明 46 #ifdef _WIN32 47 WSADATA wsa_data; 48 WSAStartup(0x0201, &wsa_data); 49 #endif 50 51 base = event_base_new(); //创建一个基底 52 if (!base) {//出错处理 53 fprintf(stderr, "Could not initialize libevent!\n"); 54 return 1; 55 } 56 //初始化服务器的地址结构 57 memset(&sin, 0, sizeof(sin)); 58 sin.sin_family = AF_INET; 59 sin.sin_port = htons(PORT); 60 //创建一个监听器,用于监听客户端的连接请求,里面的listener_cb被回调说明有新的客户端来连接,产生一个新的fd 61 listener = evconnlistener_new_bind(base, listener_cb, (void *)base, 62 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, 63 (struct sockaddr*)&sin, 64 sizeof(sin)); 65 66 if (!listener) {//出错处理 67 fprintf(stderr, "Could not create a listener!\n"); 68 return 1; 69 } 70 //创建一个信号对象,当SIGINT信号产生,signal_cb会被回调 71 signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); 72 //出错处理 73 if (!signal_event || event_add(signal_event, NULL)<0) { 74 fprintf(stderr, "Could not create/add a signal event!\n"); 75 return 1; 76 } 77 //启动循环监听 78 event_base_dispatch(base); 79 //释放资源 80 evconnlistener_free(listener); 81 event_free(signal_event); 82 event_base_free(base); 83 84 printf("done\n"); 85 return 0; 86 } 87 88 static void//参数依次是:监听器对象、新的fd、客户端的地址结构、地址结构长度、回调函数参数 89 listener_cb(struct evconnlistener *listener, evutil_socket_t fd, 90 struct sockaddr *sa, int socklen, void *user_data) 91 { 92 struct event_base *base = user_data; //通过参数将基底传递进来,创建bufferevent对象要用 93 struct bufferevent *bev; 94 //创建bufferevent事件对象,将新的fd封装在里面,事件对象有读缓冲、写缓冲 95 bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); 96 if (!bev) {//出错处理 97 fprintf(stderr, "Error constructing bufferevent!"); 98 event_base_loopbreak(base); 99 return; 100 } 101 bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);//给事件对象里面的写缓冲和事件缓冲设置回调 102 bufferevent_enable(bev, EV_WRITE);//设置为使能状态 103 bufferevent_disable(bev, EV_READ); 104 105 bufferevent_write(bev, MESSAGE, strlen(MESSAGE));相当于write函数 106 } 107 //写回调函数的具体实现,参数依次是:事件对象、bufferevent_setcb()函数中的最后一个参数,本例子中设为NULL 108 static void 109 conn_writecb(struct bufferevent *bev, void *user_data) 110 { 111 struct evbuffer *output = bufferevent_get_output(bev); 112 if (evbuffer_get_length(output) == 0) { 113 printf("flushed answer\n"); 114 bufferevent_free(bev); 115 } 116 } 117 //事件回调函数 118 static void 119 conn_eventcb(struct bufferevent *bev, short events, void *user_data) 120 { 121 if (events & BEV_EVENT_EOF) {//对端关闭 122 printf("Connection closed.\n"); 123 } else if (events & BEV_EVENT_ERROR) {//出错 124 printf("Got an error on the connection: %s\n", 125 strerror(errno));/*XXX win32*/ 126 } 127 /* None of the other events can happen here, since we haven't enabled 128 * timeouts */ 129 bufferevent_free(bev);//释放事件对象 130 } 131 //信号回调 132 static void 133 signal_cb(evutil_socket_t sig, short events, void *user_data) 134 { 135 struct event_base *base = user_data; 136 struct timeval delay = { 2, 0 };//定时器 137 138 printf("Caught an interrupt signal; exiting cleanly in two seconds.\n"); 139 140 event_base_loopexit(base, &delay);//2秒之后退出监听循环 141 }
客户端:
服务器: