11.1 HelloWorld服务器

  1. #include <string.h>
  2. #include <errno.h>
  3. #include <stdio.h>
  4. #include <signal.h>
  5. #ifndef WIN32
  6. #include <netinet/in.h>
  7. # ifdef _XOPEN_SOURCE_EXTENDED
  8. # include <arpa/inet.h>
  9. # endif
  10. #include <sys/socket.h>
  11. #endif
  12. #include <event2/bufferevent.h>
  13. #include <event2/buffer.h>
  14. #include <event2/listener.h>
  15. #include <event2/util.h>
  16. #include <event2/event.h>
  17. static const char MESSAGE[] = "Hello, World!\n";
  18. static const int PORT = 9995;
  19. static void listener_cb(struct evconnlistener *, evutil_socket_t,
  20. struct sockaddr *, int socklen, void *);
  21. static void conn_writecb(struct bufferevent *, void *);
  22. static void conn_eventcb(struct bufferevent *, short, void *);
  23. static void signal_cb(evutil_socket_t, short, void *);
  24. int
  25. main(int argc, char **argv)
  26. {
  27. struct event_base *base;
  28. struct evconnlistener *listener;
  29. struct event *signal_event;
  30. struct sockaddr_in sin;
  31. #ifdef WIN32
  32. WSADATA wsa_data;
  33. WSAStartup(0x0201, &wsa_data);
  34. #endif
  35. base = event_base_new();
  36. if (!base) {
  37. fprintf(stderr, "Could not initialize libevent!\n");
  38. return 1;
  39. }
  40. memset(&sin, 0, sizeof(sin));
  41. sin.sin_family = AF_INET;
  42. sin.sin_port = htons(PORT);
  43. listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
  44. LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
  45. (struct sockaddr*)&sin,
  46. sizeof(sin));
  47. if (!listener) {
  48. fprintf(stderr, "Could not create a listener!\n");
  49. return 1;
  50. }
  51. signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
  52. if (!signal_event || event_add(signal_event, NULL)<0) {
  53. fprintf(stderr, "Could not create/add a signal event!\n");
  54. return 1;
  55. }
  56. event_base_dispatch(base);
  57. evconnlistener_free(listener);
  58. event_free(signal_event);
  59. event_base_free(base);
  60. printf("done\n");
  61. return 0;
  62. }
  63. static void
  64. listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
  65. struct sockaddr *sa, int socklen, void *user_data)
  66. {
  67. struct event_base *base = user_data;
  68. struct bufferevent *bev;
  69. bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  70. if (!bev) {
  71. fprintf(stderr, "Error constructing bufferevent!");
  72. event_base_loopbreak(base);
  73. return;
  74. }
  75. bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
  76. bufferevent_enable(bev, EV_WRITE);
  77. bufferevent_disable(bev, EV_READ);
  78. bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
  79. }
  80. static void
  81. conn_writecb(struct bufferevent *bev, void *user_data)
  82. {
  83. struct evbuffer *output = bufferevent_get_output(bev);
  84. if (evbuffer_get_length(output) == 0) {
  85. printf("flushed answer\n");
  86. bufferevent_free(bev);
  87. }
  88. }
  89. static void
  90. conn_eventcb(struct bufferevent *bev, short events, void *user_data)
  91. {
  92. if (events & BEV_EVENT_EOF) {
  93. printf("Connection closed.\n");
  94. } else if (events & BEV_EVENT_ERROR) {
  95. printf("Got an error on the connection: %s\n",
  96. strerror(errno));/*XXX win32*/
  97. }
  98. /* None of the other events can happen here, since we haven't enabled
  99. * timeouts */
  100. bufferevent_free(bev);
  101. }
  102. static void
  103. signal_cb(evutil_socket_t sig, short events, void *user_data)
  104. {
  105. struct event_base *base = user_data;
  106. struct timeval delay = { 2, 0 };
  107. printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
  108. event_base_loopexit(base, &delay);
  109. }

11.2 基于事件服务器

11.2.1 服务端

  1. #include <event2/event-config.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <sys/queue.h>
  5. #include <unistd.h>
  6. #include <sys/time.h>
  7. #include <fcntl.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <errno.h>
  12. #include <event.h>
  13. static void
  14. fifo_read(evutil_socket_t fd, short event, void *arg)
  15. {
  16. char buf[255];
  17. int len;
  18. struct event *ev = arg;
  19. /* Reschedule this event */
  20. event_add(ev, NULL);
  21. fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
  22. (int)fd, event, arg);
  23. len = read(fd, buf, sizeof(buf) - 1);
  24. if (len == -1) {
  25. perror("read");
  26. return;
  27. } else if (len == 0) {
  28. fprintf(stderr, "Connection closed\n");
  29. return;
  30. }
  31. buf[len] = '\0';
  32. fprintf(stdout, "Read: %s\n", buf);
  33. }
  34. int
  35. main(int argc, char **argv)
  36. {
  37. struct event evfifo;
  38. struct stat st;
  39. const char *fifo = "event.fifo";
  40. int socket;
  41. if (lstat(fifo, &st) == 0) {
  42. if ((st.st_mode & S_IFMT) == S_IFREG) {
  43. errno = EEXIST;
  44. perror("lstat");
  45. exit(1);
  46. }
  47. }
  48. unlink(fifo);
  49. if (mkfifo(fifo, 0600) == -1) {
  50. perror("mkfifo");
  51. exit(1);
  52. }
  53. /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
  54. socket = open(fifo, O_RDONLY | O_NONBLOCK, 0);
  55. if (socket == -1) {
  56. perror("open");
  57. exit(1);
  58. }
  59. fprintf(stderr, "Write data to %s\n", fifo);
  60. /* Initalize the event library */
  61. event_init();
  62. /* Initalize one event */
  63. event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
  64. /* Add it to the active events, without a timeout */
  65. event_add(&evfifo, NULL);
  66. event_dispatch();
  67. return (0);
  68. }

11.2.2 客户端

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <pthread.h>
  7. int main(int argc, char *argv[])
  8. {
  9. int fd = 0;
  10. char *str = "hello libevent!";
  11. fd = open("event.fifo", O_RDWR);
  12. if (fd < 0) {
  13. perror("open error");
  14. exit(1);
  15. }
  16. while (1) {
  17. write(fd, str, strlen(str));
  18. sleep(1);
  19. }
  20. close(fd);
  21. return 0;
  22. }

11.3 回显服务器

  1. #include <event2/listener.h>
  2. #include <event2/bufferevent.h>
  3. #include <event2/buffer.h>
  4. #include <arpa/inet.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <errno.h>
  9. static void
  10. echo_read_cb(struct bufferevent *bev, void *ctx)
  11. {
  12. /* This callback is invoked when there is data to read on bev. */
  13. struct evbuffer *input = bufferevent_get_input(bev);
  14. struct evbuffer *output = bufferevent_get_output(bev);
  15. /* Copy all the data from the input buffer to the output buffer. */
  16. evbuffer_add_buffer(output, input);
  17. }
  18. static void
  19. echo_event_cb(struct bufferevent *bev, short events, void *ctx)
  20. {
  21. if (events & BEV_EVENT_ERROR)
  22. perror("Error from bufferevent");
  23. if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
  24. bufferevent_free(bev);
  25. }
  26. }
  27. static void
  28. accept_conn_cb(struct evconnlistener *listener,
  29. evutil_socket_t fd, struct sockaddr *address, int socklen,
  30. void *ctx)
  31. {
  32. /* We got a new connection! Set up a bufferevent for it. */
  33. struct event_base *base = evconnlistener_get_base(listener);
  34. struct bufferevent *bev = bufferevent_socket_new(
  35. base, fd, BEV_OPT_CLOSE_ON_FREE);
  36. bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);
  37. bufferevent_enable(bev, EV_READ|EV_WRITE);
  38. }
  39. static void
  40. accept_error_cb(struct evconnlistener *listener, void *ctx)
  41. {
  42. struct event_base *base = evconnlistener_get_base(listener);
  43. int err = EVUTIL_SOCKET_ERROR();
  44. fprintf(stderr, "Got an error %d (%s) on the listener. "
  45. "Shutting down.\n", err, evutil_socket_error_to_string(err));
  46. event_base_loopexit(base, NULL);
  47. }
  48. int
  49. main(int argc, char **argv)
  50. {
  51. struct event_base *base;
  52. struct evconnlistener *listener;
  53. struct sockaddr_in sin;
  54. int port = 9876;
  55. if (argc > 1) {
  56. port = atoi(argv[1]);
  57. }
  58. if (port<=0 || port>65535) {
  59. puts("Invalid port");
  60. return 1;
  61. }
  62. base = event_base_new();
  63. if (!base) {
  64. puts("Couldn't open event base");
  65. return 1;
  66. }
  67. /* Clear the sockaddr before using it, in case there are extra
  68. * platform-specific fields that can mess us up. */
  69. memset(&sin, 0, sizeof(sin));
  70. /* This is an INET address */
  71. sin.sin_family = AF_INET;
  72. /* Listen on 0.0.0.0 */
  73. sin.sin_addr.s_addr = htonl(0);
  74. /* Listen on the given port. */
  75. sin.sin_port = htons(port);
  76. listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
  77. LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
  78. (struct sockaddr*)&sin, sizeof(sin));
  79. if (!listener) {
  80. perror("Couldn't create listener");
  81. return 1;
  82. }
  83. evconnlistener_set_error_cb(listener, accept_error_cb);
  84. event_base_dispatch(base);
  85. return 0;
  86. }

11.4 http服务器

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> //for getopt, fork
  4. #include <string.h> //for strcat
  5. //for struct evkeyvalq
  6. #include <sys/queue.h>
  7. #include <event.h>
  8. //for http
  9. //#include <evhttp.h>
  10. #include <event2/http.h>
  11. #include <event2/http_struct.h>
  12. #include <event2/http_compat.h>
  13. #include <event2/util.h>
  14. #include <signal.h>
  15. #define MYHTTPD_SIGNATURE "myhttpd v 0.0.1"
  16. //处理模块
  17. void httpd_handler(struct evhttp_request *req, void *arg) {
  18. char output[2048] = "\0";
  19. char tmp[1024];
  20. //获取客户端请求的URI(使用evhttp_request_uri或直接req->uri)
  21. const char *uri;
  22. uri = evhttp_request_uri(req);
  23. sprintf(tmp, "uri=%s\n", uri);
  24. strcat(output, tmp);
  25. sprintf(tmp, "uri=%s\n", req->uri);
  26. strcat(output, tmp);
  27. //decoded uri
  28. char *decoded_uri;
  29. decoded_uri = evhttp_decode_uri(uri);
  30. sprintf(tmp, "decoded_uri=%s\n", decoded_uri);
  31. strcat(output, tmp);
  32. //解析URI的参数(即GET方法的参数)
  33. struct evkeyvalq params;
  34. //将URL数据封装成key-value格式,q=value1, s=value2
  35. evhttp_parse_query(decoded_uri, &params);
  36. //得到q所对应的value
  37. sprintf(tmp, "q=%s\n", evhttp_find_header(&params, "q"));
  38. strcat(output, tmp);
  39. //得到s所对应的value
  40. sprintf(tmp, "s=%s\n", evhttp_find_header(&params, "s"));
  41. strcat(output, tmp);
  42. free(decoded_uri);
  43. //获取POST方法的数据
  44. char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
  45. sprintf(tmp, "post_data=%s\n", post_data);
  46. strcat(output, tmp);
  47. /*
  48. 具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出
  49. ...
  50. */
  51. /* 输出到客户端 */
  52. //HTTP header
  53. evhttp_add_header(req->output_headers, "Server", MYHTTPD_SIGNATURE);
  54. evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8");
  55. evhttp_add_header(req->output_headers, "Connection", "close");
  56. //输出的内容
  57. struct evbuffer *buf;
  58. buf = evbuffer_new();
  59. evbuffer_add_printf(buf, "It works!\n%s\n", output);
  60. evhttp_send_reply(req, HTTP_OK, "OK", buf);
  61. evbuffer_free(buf);
  62. }
  63. void show_help() {
  64. char *help = "http://localhost:8080\n"
  65. "-l <ip_addr> interface to listen on, default is 0.0.0.0\n"
  66. "-p <num> port number to listen on, default is 1984\n"
  67. "-d run as a deamon\n"
  68. "-t <second> timeout for a http request, default is 120 seconds\n"
  69. "-h print this help and exit\n"
  70. "\n";
  71. fprintf(stderr,"%s",help);
  72. }
  73. //当向进程发出SIGTERM/SIGHUP/SIGINT/SIGQUIT的时候,终止event的事件侦听循环
  74. void signal_handler(int sig) {
  75. switch (sig) {
  76. case SIGTERM:
  77. case SIGHUP:
  78. case SIGQUIT:
  79. case SIGINT:
  80. event_loopbreak(); //终止侦听event_dispatch()的事件侦听循环,执行之后的代码
  81. break;
  82. }
  83. }
  84. int main(int argc, char *argv[]) {
  85. //自定义信号处理函数
  86. signal(SIGHUP, signal_handler);
  87. signal(SIGTERM, signal_handler);
  88. signal(SIGINT, signal_handler);
  89. signal(SIGQUIT, signal_handler);
  90. //默认参数
  91. char *httpd_option_listen = "0.0.0.0";
  92. int httpd_option_port = 8080;
  93. int httpd_option_daemon = 0;
  94. int httpd_option_timeout = 120; //in seconds
  95. //获取参数
  96. int c;
  97. while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) {
  98. switch (c) {
  99. case 'l' :
  100. httpd_option_listen = optarg;
  101. break;
  102. case 'p' :
  103. httpd_option_port = atoi(optarg);
  104. break;
  105. case 'd' :
  106. httpd_option_daemon = 1;
  107. break;
  108. case 't' :
  109. httpd_option_timeout = atoi(optarg);
  110. break;
  111. case 'h' :
  112. default :
  113. show_help();
  114. exit(EXIT_SUCCESS);
  115. }
  116. }
  117. //判断是否设置了-d,以daemon运行
  118. if (httpd_option_daemon) {
  119. pid_t pid;
  120. pid = fork();
  121. if (pid < 0) {
  122. perror("fork failed");
  123. exit(EXIT_FAILURE);
  124. }
  125. if (pid > 0) {
  126. //生成子进程成功,退出父进程
  127. exit(EXIT_SUCCESS);
  128. }
  129. }
  130. /* 使用libevent创建HTTP Server */
  131. //初始化event API
  132. event_init();
  133. //创建一个http server
  134. struct evhttp *httpd;
  135. httpd = evhttp_start(httpd_option_listen, httpd_option_port);
  136. evhttp_set_timeout(httpd, httpd_option_timeout);
  137. //指定generic callback
  138. evhttp_set_gencb(httpd, httpd_handler, NULL);
  139. //也可以为特定的URI指定callback
  140. //evhttp_set_cb(httpd, "/", specific_handler, NULL);
  141. //循环处理events
  142. event_dispatch();
  143. evhttp_free(httpd);
  144. return 0;
  145. }