使用libevent编写高并发HTTP server

来源:互联网 发布:人工智能带来的问题 编辑:程序博客网 时间:2024/05/18 02:33

http://www.cnblogs.com/keepsimple/archive/2013/05/06/3063251.html     

http://blog.csdn.net/liuhongxiangm/article/details/14230763

  libevent库使得高并发响应HTTP Server的编写变得很容易。整个过程包括如下几部:初始化,创建HTTP Server, 指定callback, 进入事件循环。另外在回调函数中,可以获取客户端请求(request的HTTP Header和参数等),进行响应的处理,再将结果发送给客户端(response的HTTP Header和内容,如html代码)。

libevent除了设置generic的callback,还可以对特定的请求路径设置对应的callback(回调/处理函数)。

示例代码(方便日后参考编写需要的HTTP server)

    #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 <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;        evhttp_parse_query(decoded_uri, &params);        sprintf(tmp, "q=%s\n", evhttp_find_header(&params, "q"));        strcat(output, tmp);        sprintf(tmp, "s=%s\n", evhttp_find_header(&params, "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 = "written by Min (http://54min.com)\n\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, 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;    }
  • 编译:gcc -o myhttpd -Wall -levent myhttpd.c
  • 运行:./test
  • 测试:

在浏览器中输入http://54min.com:8080/index.php?q=test&s=some thing,显示内容如下:

    It works!    uri=/index.php?q=test&s=some%20thing    uri=/index.php?q=test&s=some%20thing    decoded_uri=/index.php?q=test&s=some thing    q=test    s=some thing    post_data=(null)

并使用Live Http Headers(Firefox addons)查看HTTP headers。

    HTTP/1.1 200 OK    Server: myhttpd v 0.0.1    Content-Type: text/plain; charset=UTF-8    Connection: close    Date: Tue, 21 Jun 2011 06:30:30 GMT    Content-Length: 72
原文地址:http://www.cnblogs.com/keepsimple/archive/2013/05/06/3063251.html
0 0
原创粉丝点击