10.3 libevent实现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. }