libevent(九)evhttp

用libevent構建一個http server很是方便,可參考libevent(六)http serverhtml

主要涉及的一個結構體是evhttp:多線程

struct evhttp {
    /* Next vhost, if this is a vhost. */
    TAILQ_ENTRY(evhttp) next_vhost;

    /* All listeners for this host */
    TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;

    TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;

    /* All live connections on this host. */
    struct evconq connections;

    TAILQ_HEAD(vhostsq, evhttp) virtualhosts;

    TAILQ_HEAD(aliasq, evhttp_server_alias) aliases;

    /* NULL if this server is not a vhost */
    char *vhost_pattern;

    int timeout;

    size_t default_max_headers_size;
    ev_uint64_t default_max_body_size;

    /* Bitmask of all HTTP methods that we accept and pass to user
     * callbacks. */
    ev_uint16_t allowed_methods;

    /* Fallback callback if all the other callbacks for this connection
       don't match. */
    void (*gencb)(struct evhttp_request *req, void *);
    void *gencbarg;

    struct event_base *base;
};

值得關注的有兩個成員:
  callbacks,一個鏈表,存放用戶定義的回調函數
  connections,一個鏈表,存放全部鏈接,每一個鏈接對應一個evhttp_connectionsocket

evhttp_connection結構以下:函數

/* A client or server connection. */
struct evhttp_connection {
    /* we use this tailq only if this connection was created for an http
     * server */
    TAILQ_ENTRY(evhttp_connection) next;

    evutil_socket_t fd;
    struct bufferevent *bufev;

    struct event retry_ev;        /* for retrying connects */

    char *bind_address;        /* address to use for binding the src */
    u_short bind_port;        /* local port for binding the src */

    char *address;            /* address to connect to */
    u_short port;

    size_t max_headers_size;
    ev_uint64_t max_body_size;

    int flags;
#define EVHTTP_CON_INCOMING    0x0001    /* only one request on it ever */
#define EVHTTP_CON_OUTGOING    0x0002  /* multiple requests possible */
#define EVHTTP_CON_CLOSEDETECT  0x0004  /* detecting if persistent close */

    int timeout;            /* timeout in seconds for events */
    int retry_cnt;            /* retry count */
    int retry_max;            /* maximum number of retries */

    enum evhttp_connection_state state;

    /* for server connections, the http server they are connected with */
    struct evhttp *http_server;

    TAILQ_HEAD(evcon_requestq, evhttp_request) requests;

    void (*cb)(struct evhttp_connection *, void *);
    void *cb_arg;

    void (*closecb)(struct evhttp_connection *, void *);
    void *closecb_arg;

    struct deferred_cb read_more_deferred_cb;

    struct event_base *base;
    struct evdns_base *dns_base;
};

值得關注的成員有兩個:
  bufev,對應一個bufferevent
  requests,一個鏈表,存放該鏈接上的全部請求,每一個請求對應evhttp_requestpost

evhttp_request結構以下:ui

struct evhttp_request {
#if defined(TAILQ_ENTRY)
    TAILQ_ENTRY(evhttp_request) next;
#else
struct {
    struct evhttp_request *tqe_next;
    struct evhttp_request **tqe_prev;
}       next;
#endif

    /* the connection object that this request belongs to */
    struct evhttp_connection *evcon;
    int flags;
/** The request obj owns the evhttp connection and needs to free it */
#define EVHTTP_REQ_OWN_CONNECTION    0x0001
/** Request was made via a proxy */
#define EVHTTP_PROXY_REQUEST        0x0002
/** The request object is owned by the user; the user must free it */
#define EVHTTP_USER_OWNED        0x0004
/** The request will be used again upstack; freeing must be deferred */
#define EVHTTP_REQ_DEFER_FREE        0x0008
/** The request should be freed upstack */
#define EVHTTP_REQ_NEEDS_FREE        0x0010

    struct evkeyvalq *input_headers;
    struct evkeyvalq *output_headers;

    /* address of the remote host and the port connection came from */
    char *remote_host;
    ev_uint16_t remote_port;

    /* cache of the hostname for evhttp_request_get_host */
    char *host_cache;

    enum evhttp_request_kind kind;
    enum evhttp_cmd_type type;

    size_t headers_size;
    size_t body_size;

    char *uri;            /* uri after HTTP request was parsed */
    struct evhttp_uri *uri_elems;    /* uri elements */

    char major;            /* HTTP Major number */
    char minor;            /* HTTP Minor number */

    int response_code;        /* HTTP Response code */
    char *response_code_line;    /* Readable response */

    struct evbuffer *input_buffer;    /* read data */
    ev_int64_t ntoread;
    unsigned chunked:1,        /* a chunked request */
        userdone:1;            /* the user has sent all data */

    struct evbuffer *output_buffer;    /* outgoing post or data */

    /* Callback */
    void (*cb)(struct evhttp_request *, void *);
    void *cb_arg;

    /*
     * Chunked data callback - call for each completed chunk if
     * specified.  If not specified, all the data is delivered via
     * the regular callback.
     */
    void (*chunk_cb)(struct evhttp_request *, void *);
}; 

值得注意的是:
  每一個請求有本身的輸入緩衝input_buffer、輸出緩衝output_buffer。this


總結一下evhttp:
  1. 一個evhttp使用一個鏈表存放多個evhttp_connection,每一個evhttp_connection使用鏈表存放多個evhttp_request。
  2. 每一個evhttp_connection包含一個bufferevent,每一個evhttp_request包含兩個evbuffer,用於輸入輸出緩衝。url

 

說了半天,好像沒看見同步機制,可見evhttp不適合多線程。spa

 

參考資料:線程

libevent源碼淺析: http庫

相關文章
相關標籤/搜索