zoukankan      html  css  js  c++  java
  • libevhtp初探

    libevent的evhttp不适合多线程,libevhtp重新设计了libevent的http API,采用了和memcached类似的多线程模型。

    worker线程的管道读事件的回调函数为htp__run_in_thread_:

    #ifndef EVHTP_DISABLE_EVTHR
    static void
    htp__run_in_thread_(evthr_t * thr, void * arg, void * shared)
    {
        evhtp_t            * htp        = shared;
        evhtp_connection_t * connection = arg;
    
        connection->evbase = evthr_get_base(thr);
        connection->thread = thr;
    
        if (htp__connection_accept_(connection->evbase, connection) < 0)
        {
            evhtp_connection_free(connection);
    
            return;
        }
    
        if (htp__run_post_accept_(htp, connection) < 0)
        {
            evhtp_connection_free(connection);
    
            return;
        }
    }
    
    #endif

    htp__connection_accept_函数如下:

    static int
    htp__connection_accept_(struct event_base * evbase, evhtp_connection_t * connection)
    {
        struct timeval * c_recv_timeo;
        struct timeval * c_send_timeo;
    
        if (htp__run_pre_accept_(connection->htp, connection) < 0)
        {
            evutil_closesocket(connection->sock);
    
            return -1;
        }
    
    #ifndef EVHTP_DISABLE_SSL
        if (connection->htp->ssl_ctx != NULL)
        {
            connection->ssl = SSL_new(connection->htp->ssl_ctx);
            connection->bev = bufferevent_openssl_socket_new(evbase,
                                                             connection->sock,
                                                             connection->ssl,
                                                             BUFFEREVENT_SSL_ACCEPTING,
                                                             connection->htp->bev_flags);
            SSL_set_app_data(connection->ssl, connection);
            goto end;
        }
    #endif
    
        connection->bev = bufferevent_socket_new(evbase,
                                                 connection->sock,
                                                 connection->htp->bev_flags);
    
        htp_log_debug("enter sock=%d
    ", connection->sock);
    
    #ifndef EVHTP_DISABLE_SSL
    end:
    #endif
    
        if (connection->recv_timeo.tv_sec || connection->recv_timeo.tv_usec)
        {
            c_recv_timeo = &connection->recv_timeo;
        } else if (connection->htp->recv_timeo.tv_sec ||
                   connection->htp->recv_timeo.tv_usec)
        {
            c_recv_timeo = &connection->htp->recv_timeo;
        } else {
            c_recv_timeo = NULL;
        }
    
        if (connection->send_timeo.tv_sec || connection->send_timeo.tv_usec)
        {
            c_send_timeo = &connection->send_timeo;
        } else if (connection->htp->send_timeo.tv_sec ||
                   connection->htp->send_timeo.tv_usec)
        {
            c_send_timeo = &connection->htp->send_timeo;
        } else {
            c_send_timeo = NULL;
        }
    
        evhtp_connection_set_timeouts(connection, c_recv_timeo, c_send_timeo);
    
        connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
                                          htp__connection_resumecb_, connection);
        event_add(connection->resume_ev, NULL);
    
        bufferevent_enable(connection->bev, EV_READ);
        bufferevent_setcb(connection->bev,
                          htp__connection_readcb_,
                          htp__connection_writecb_,
                          htp__connection_eventcb_, connection);
    
        return 0;
    } 

    此时,conn_fd的读事件已经添加到worker线程的event_base中。

     

    当读事件发生后,最终会运行htp__connection_readcb_,然后调用htparser_run,再调用htp__request_parse_path_:

    static int
    htp__request_parse_path_(htparser * p, const char * data, size_t len)
    {
        evhtp_connection_t * c = htparser_get_userdata(p);
        evhtp_path_t       * path;
    
        if (htp__require_uri_(c) != 0)
        {
            return -1;
        }
    
        if (evhtp_unlikely(!(path = htp__path_new_(data, len))))
        {
            c->request->status = EVHTP_RES_FATAL;
    
            return -1;
        }
    
        c->request->uri->path   = path;
        c->request->uri->scheme = htparser_get_scheme(p);
        c->request->method      = htparser_get_method(p);
    
        htp__lock_(c->htp);
        {
            htp__request_set_callbacks_(c->request);
        }
        htp__unlock_(c->htp);
    
        if ((c->request->status = htp__hook_path_(c->request, path)) != EVHTP_RES_OK)
        {
            return -1;
        }
    
        return 0;
    }

    通过htp__request_set_callbacks_,我们可以设置每个请求的回调函数为evhtp_s结构中的回调函数。

    htparser_run后续会调用htp__request_parse_fini_:

    static int
    htp__request_parse_fini_(htparser * p)
    {
        evhtp_connection_t * c = htparser_get_userdata(p);
    
        if (c->flags & EVHTP_CONN_FLAG_PAUSED)
        {
            return -1;
        }
    
        /* check to see if we should use the body of the request as the query
         * arguments.
         */
        if (htp__should_parse_query_body_(c->request) == 1)
        {
            const char      * body;
            size_t            body_len;
            evhtp_uri_t     * uri;
            struct evbuffer * buf_in;
    
            uri            = c->request->uri;
            buf_in         = c->request->buffer_in;
    
            body_len       = evbuffer_get_length(buf_in);
            body           = (const char *)evbuffer_pullup(buf_in, body_len);
    
            uri->query_raw = calloc(body_len + 1, 1);
            evhtp_alloc_assert(uri->query_raw);
    
            memcpy(uri->query_raw, body, body_len);
    
            uri->query     = evhtp_parse_query(body, body_len);
        }
    
    
        /*
         * XXX c->request should never be NULL, but we have found some path of
         * execution where this actually happens. We will check for now, but the bug
         * path needs to be tracked down.
         *
         */
        if (c->request && c->request->cb)
        {
            (c->request->cb)(c->request, c->request->cbarg);
        }
    
        if (c->flags & EVHTP_CONN_FLAG_PAUSED)
        {
            return -1;
        }
    
        return 0;
    }

    可以看到,最终request的回调函数被执行。

  • 相关阅读:
    Understanding about Baire Category Theorem
    Isometric embedding of metric space
    Convergence theorems for measurable functions
    Mindmap for "Principles of boundary element methods"
    Various formulations of Maxwell equations
    Existence and uniqueness theorems for variational problems
    Kernels and image sets for an operator and its dual
    [loj6498]农民
    [luogu3781]切树游戏
    [atAGC051B]Three Coins
  • 原文地址:https://www.cnblogs.com/gattaca/p/6929601.html
Copyright © 2011-2022 走看看