libevent(九)evhttp

用libevent构建一个http server非常方便,可参考libevent(六)http server

主要涉及的一个结构体是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_connection

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_request

evhttp_request结构如下:

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。


总结一下evhttp:
  1. 一个evhttp使用一个链表存放多个evhttp_connection,每个evhttp_connection使用链表存放多个evhttp_request。
  2. 每个evhttp_connection包含一个bufferevent,每个evhttp_request包含两个evbuffer,用于输入输出缓冲。

 

说了半天,好像没看见同步机制,可见evhttp不适合多线程。

 

参考资料:

libevent源码浅析: http库

posted @ 2017-05-22 12:03  Sawyer Ford  阅读(3023)  评论(0编辑  收藏  举报