libevent 를 사용 하여 높 은 병렬 HTTP server 를 작성 합 니 다.

13044 단어 libevent
libevent 라 이브 러 리 는 HTTP 서버 에 대한 높 은 동시 응답 을 쉽게 만 들 었 습 니 다.전체 과정 은 다음 과 같은 몇 가 지 를 포함한다.초기 화,HTTP 서버 생 성,콜백 지정,이벤트 순환 에 들어간다.또한 리 셋 함수 에서 클 라 이언 트 요청(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
", uri); strcat(output, tmp); sprintf(tmp, "uri=%s
", req->uri); strcat(output, tmp); //decoded uri char *decoded_uri; decoded_uri = evhttp_decode_uri(uri); sprintf(tmp, "decoded_uri=%s
", decoded_uri); strcat(output, tmp); // URI ( GET ) struct evkeyvalq params; evhttp_parse_query(decoded_uri, &params); sprintf(tmp, "q=%s
", evhttp_find_header(&params, "q")); strcat(output, tmp); sprintf(tmp, "s=%s
", 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
", 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!
%s
", output); evhttp_send_reply(req, HTTP_OK, "OK", buf); evbuffer_free(buf); } void show_help() { char *help = "written by Min (http://54min.com)

" "-l <ip_addr> interface to listen on, default is 0.0.0.0
" "-p <num> port number to listen on, default is 1984
" "-d run as a deamon
" "-t <second> timeout for a http request, default is 120 seconds
" "-h print this help and exit
" "
"; 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

    libevent 라 이브 러 리 를 사용 하여 HTTP 패 키 징 방법 을 적용 합 니 다.
    libevent 라 이브 러 리 는 고성능 HTTP 서버 를 쉽게 만 들 었 습 니 다.따라서 실제 libevent 를 사용 하면 모든 응용(예 를 들 어 데이터베이스)에 HTTP based 네트워크 인 터 페 이 스 를 제공 하여 여러 클 라 이언 트 가 HTTP protocol 을 지원 하 는 언어 로 server 와 상호작용 하 는 데 편리 합 니 다.예 를 들 면:
    HTTP 프로 토 콜 이 지원 되 지 않 는 데이터베이스(RDBMS/NoSQL)패 키 징 HTTP 인터페이스
  • Memcached Server 는 기본적으로 Memcached Protocol 을 지원 합 니 다.libmemcached 라 이브 러 리 와 libevent 라 이브 러 리 를 통 해 Memcached Server 에 HTTP 인 터 페 이 스 를 밀봉 하여 client 단 은 HTTP 프로 토 콜 과 Memcached Server 를 통 해 상호작용 을 할 수 있 습 니 다.레 퍼 런 스
  • 도 쿄 Cabinet/Tokyo Tyrant 데이터베이스 에 HTTP 인 터 페 이 스 를 밀봉 하여 client 단 과 의 상호작용 을 편리 하 게 할 수 있 습 니 다.레 퍼 런 스
  • 같은 경우 MySQL,Redis,MongoDB 등 다른 데이터 베 이 스 를 위해 HTTP 인 터 페 이 스 를 봉인 할 수 있 습 니 다.

  • 더 많은 이 응용 은 참고 할 수 있다.https://github.com/bitly/simplehttp.
    또한 일부 응용 프로그램 에 HTTP 인 터 페 이 스 를 패키지 하여 client/server 방식 으로 사용 할 수 있 습 니 다.
  • HTTPCWSlibevent 로 중국어 단어 프로그램 을 패키지 하여 client/server 방식 으로 단어 기능 사용
  • HTTP-SCWS도 비슷 한 방식
  • 첨부:관련 된 데이터 구조 와 주요 함수
    데이터 구조
  • struct evhttp_request

  • 클 라 이언 트 요청 표시,정의 참조:http://monkey.org/~provos/libevent/doxygen-1.4.10/structevhttp__request.html,그 안에 포 함 된 주요 도 메 인:
        struct evkeyvalq *input_headers;    //        HTTP headers(key-value pairs)
    
        struct evkeyvalq *output_headers;   //           HTTP headers(key-value pairs)
    
    
    
        //    ip port
    
        char *remote_host;
    
        u_short remote_port;
    
    
    
        enum evhttp_request_kind kind;  //   EVHTTP_REQUEST EVHTTP_RESPONSE
    
        enum evhttp_cmd_type type;  //   EVHTTP_REQ_GET, EVHTTP_REQ_POST EVHTTP_REQ_HEAD
    
    
    
        char *uri;          //      uri
    
        char major;         //HTTP major number
    
        char minor;         //HTTP major number
    
    
    
        int response_code;      //HTTP response code
    
        char *response_code_line;   //readable response
    
    
    
        struct evbuffer *input_buffer;  //   POST   
    
        struct evbuffer *output_buffer; //         
  • struct evkeyvalq

  • 정의 참조:http://monkey.org/~provos/libevent/doxygen-1.4.10/event_8h-source.html。 struct evkeyvalqTAILQ_HEAD (evkeyvalq, evkeyval);,즉struct evkeyval유형의 tail quue 로 정의 된다.코드 전에 포함해 야 합 니 다.
        #include <sys/queue.h>
    
        #include <event.h>
    struct evkeyval는 key-value quue(대기 열 구조)로 주로 HTTP headers 를 저장 하고 parse uri 인자 의 결 과 를 저장 할 수 있 습 니 다.
        /* Key-Value pairs.  Can be used for HTTP headers but also for query argument parsing. */
    
        struct evkeyval {
    
            TAILQ_ENTRY(evkeyval) next; //  
    
            char *key;
    
            char *value;
    
        };

    매크로TAILQ_ENTRY(evkeyval)는 다음 과 같이 정의 되 었 습 니 다.
        #define TAILQ_ENTRY(type)
    
        struct {
    
            struct type *tqe_next;      //next element
    
            struct type **tqe_prev;     //address of previous next element
    
        }
  • stuct evbuffer

  • 정의 참조:http://monkey.org/~provos/libevent/doxygen-1.4.10/event_8h-source.html。이 구조 체 는 input 와 output 의 buffer 에 사용 된다.
        /* These functions deal with buffering input and output */
    
        struct evbuffer {
    
            u_char *buffer;
    
            u_char *orig_buffer;
    
            size_t misalign;
    
            size_t totallen;
    
            size_t off;
    
            void (*cb)(struct evbuffer *, size_t, size_t, void *);
    
            void *cbarg;
    
        };

    또한 매크로 를 정의 하여 evbuffer 에 저 장 된 내용 과 크기 를 쉽게 가 져 올 수 있 습 니 다.
        #define EVBUFFER_LENGTH(x)      (x)->off
    
        #define EVBUFFER_DATA(x)        (x)->buffer

    예 를 들 어 클 라 이언 트 POST 데이터 의 내용 과 크기 를 가 져 옵 니 다.
        EVBUFFER_DATA(res->input_buffer);
    
        EVBUFFER_LENGTH(res->input_buffer);

    또한struct evbuffer다음 함수 로 추가 와 방출 을 만 듭 니 다.
        struct evbuffer *buf;
    
        buf = evbuffer_new();
    
        // buffer     
    
        evbuffer_add_printf(buf, "It works! you just requested: %s
    ", req->uri); //Append a formatted string to the end of an evbuffer. // evhttp_send_reply(req, HTTP_OK, "OK", buf); // buf evbuffer_free(buf);

    관건 함수
  • 클 라 이언 트 가 요청 한 URI 가 져 오기
  • 사용req->uri또는 사용 함수const char *evhttp_request_uri(struct evhttp_request *req);evhttp_request_uri(req);.
  • 획득 한 URI 분석 및 기타 조작
  • 함수void evhttp_parse_query(const char *uri, struct evkeyvalq *args);를 사용 하여 uri 의 인 자 를 분석 할 수 있 습 니 다.결 과 는struct evkeyvalq의 key-value pairs 에 저 장 됩 니 다.예 를 들 어:
        char *uri = "http://foo.com/?q=test&s=some+thing";
    
        struct evkeyvalq args;
    
        evhttp_parse_query(uri, &args);
    
        //    evhttp_find_header              
    
        evhttp_find_header(&args, "q"); //  test
    
        evhttp_find_header(&args, "s"); //  some thing      

    다음 두 함수 가 URI 에 대해 encode 와 decode 를 진행 합 니 다.
        char *evhttp_encode_uri(const char *uri);
    
        char *evhttp_decode_uri(const char *uri);

    URI encode 의 결 과 는 모든 비 alphanumeric 및-_문자 가%와 2 비트 16 진수 문자 로 바 뀌 었 습 니 다.위의 두 함수 가 되 돌아 오 는 문자열 은+떨 어 뜨 려 야 합 니 다.
  • HTTP headers 와 관련 된 함수 처리
  • HTTP headers 는free의 구조 체 에 저 장 됩 니 다(key-value pairs).다음 함수 로 수정 할 수 있 습 니 다.
        const char *evhttp_find_header(const struct evkeyvalq *, const char *);
    
        int evhttp_remove_header(struct evkeyvalq *, const char *);
    
        int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
    
        void evhttp_clear_headers(struct evkeyvalq *);
  • Escape 의 특별한 HTML 문자
    char *evhttp_htmlescape(const char *html);
  • 특수 문자:struct evkeyvalq&로 바 뀌 었 습 니 다.&amp;이 교체";&quot;이 교체';&#039;이 교체<;&lt;>로 교체 됐다.이 함수 가 되 돌아 오 는 문자열 은&gt;떨 어 뜨 려 야 합 니 다.
    다음으로 전송:http://note.sdo.com/u/1730579924/n/D9ETk~jLB38MLX0a8000TB

    좋은 웹페이지 즐겨찾기