Libevent (13) Evhttp Event Processing flow

Source: Internet
Author: User

In Libevent (vi) HTTP server, as a single-threaded HTTP server, listen not only to the arrival of each connection, but also to the I/O events on each connection.

Check the source, in Evhttp_bind_socket set the Accept callback function:ACCEPT_SOCKET_CB.

/**/staticvoidACCEPT_SOCKET_CB (structstruct  intvoid *arg) {    struct evhttp *http = arg;    Evhttp_get_request (http, NFD, Peer_sa, Peer_socklen);}

Static voidEvhttp_get_request (structEvhttp *http, evutil_socket_t FD,structSOCKADDR *SA, ev_socklen_t Salen) {    structEvhttp_connection *Evcon; Evcon=evhttp_get_request_connection (http, FD, SA, salen); if(Evcon = =NULL) {Event_sock_warn (FD,"%s:cannot get connection on"ev_sock_fmt, __func__, Ev_sock_arg (FD));        Evutil_closesocket (FD); return; }    /*The timeout can be used by the server to close idle connections*/    if(Http->timeout! =-1) evhttp_connection_set_timeout (Evcon, HTTP-timeout); /** If we want to accept more than one request in a connection, * we need to know which HTTP server it belongs     To. */Evcon->http_server =http; Tailq_insert_tail (&http->connections, Evcon, next); if(Evhttp_associate_new_request_with_connection (evcon) = =-1) Evhttp_connection_free (Evcon);}

Two important functions: evhttp_get_request_connection,evhttp_associate_new_request_with_connection .

1. evhttp_get_request_connection

/** Takes A file descriptor to read a request from. * The callback was executed once the whole request has been read. /c11>*/Static structevhttp_connection*Evhttp_get_request_connection (structevhttp*http, evutil_socket_t FD,structSOCKADDR *SA, ev_socklen_t Salen) {    structEvhttp_connection *Evcon; Char*hostname = NULL, *portname =NULL; NAME_FROM_ADDR (SA, Salen,&hostname, &portname); if(hostname = = NULL | | portname = =NULL) {        if(hostname) Mm_free (hostname); if(PortName) mm_free (portname); return(NULL); } event_debug (("%s:new request from%s:%s on"Ev_sock_fmt"\ n", __FUNC__, hostname, portname, Ev_sock_arg (FD)); /*We need a connection object to put the HTTP request on*/Evcon=evhttp_connection_base_new (http-Base, NULL, hostname, atoi (portname));    Mm_free (hostname);    Mm_free (PortName); if(Evcon = =NULL)return(NULL); Evcon->max_headers_size = http->default_max_headers_size; Evcon->max_body_size = http->default_max_body_size; Evcon->flags |=evhttp_con_incoming; Evcon->state =Evcon_reading_firstline; Evcon->FD =FD; bufferevent_setfd (Evcon ->bufev, FD); return(Evcon);}

Note the point:

1. bufferevent READCD is set through Evhttp_connection_base_new: EVHTTP_READ_CB,

WRITECB: EVHTTP_WRITE_CB.

2. Call BUFFEREVENT_SETFD

The BUFFEREVENT_SETFD code is as follows:

intBufferevent_setfd (structBufferevent *Bev, evutil_socket_t FD)    {Union Bufferevent_ctrl_data D; intres =-1; D.FD=FD;    Bev_lock (BEV); if(bev->be_ops->ctrl) Res= Bev->be_ops->ctrl (Bev, BEV_CTRL_SET_FD, &d);    Bev_unlock (BEV); returnRes;}Static intBe_socket_ctrl (structBufferevent *bev,enumbufferevent_ctrl_op op, Union bufferevent_ctrl_data*data) {    Switch(OP) { Casebev_ctrl_set_fd:be_socket_setfd (BEV, Data-FD); return 0;  CaseBev_ctrl_get_fd:data->FD = EVENT_GET_FD (&bev->ev_read); return 0;  Casebev_ctrl_get_underlying: CaseBev_ctrl_cancel_all:default:        return-1; }}Static voidBe_socket_setfd (structBufferevent *Bufev, evutil_socket_t FD)    {Bev_lock (BUFEV); Evutil_assert (Bufev->be_ops = = &bufferevent_ops_socket); Event_del (&bufev->ev_read); Event_del (&bufev->ev_write); Event_assign (&bufev->ev_read, bufev->ev_base, FD, Ev_read|ev_persist, BUFFEREVENT_READCB, Bufev); Event_assign (&bufev->ev_write, bufev->ev_base, FD, Ev_write|ev_persist, BUFFEREVENT_WRITECB, Bufev); if(FD >=0) bufferevent_enable (Bufev, Bufev-enabled); Bev_unlock (Bufev);}

Here the main set of FD read event callback BUFFEREVENT_READCB, write event callback BUFFEREVENT_WRITECB.

( here the bufferevent_enable can not be cared for, the back will be reset.) )

2. evhttp_associate_new_request_with_connection

Static intEvhttp_associate_new_request_with_connection (structEvhttp_connection *Evcon) {    structEvhttp *http = evcon->Http_server; structEvhttp_request *req; if((req = evhttp_request_new (evhttp_handle_request, http)) = =NULL)return(-1); if((Req->remote_host = Mm_strdup (evcon->address)) = =NULL) {Event_warn ("%s:strdup", __func__);        Evhttp_request_free (req); return(-1); } req->remote_port = evcon->Port; Req->evcon = Evcon;/*The request ends up owning the connection*/req->flags |=evhttp_req_own_connection; /*We didn't present the request to the user user yet, so treat it as * if the user is done with the request. This allows us to free the * request on a persistent connection if the client drops it without * sending a request     . */req->userdone =1; Tailq_insert_tail (&evcon->requests, req, next); Req->kind =evhttp_request;    Evhttp_start_read (Evcon); return(0);}

The first step is to set Evhttp_request's callback function evhttp_handle_request, and the second step calls Evhttp_start_read:

/** Reads data from file descriptor into request structure * Request structure needs to BES set up correctly.*/voidEvhttp_start_read (structEvhttp_connection *Evcon) {    /*Set up a event to read the headers*/bufferevent_disable (Evcon-Bufev, Ev_write); Bufferevent_enable (Evcon-Bufev, Ev_read); Evcon->state =Evcon_reading_firstline; /*Reset the bufferevent callbacks*/BUFFEREVENT_SETCB (Evcon-Bufev, EVHTTP_READ_CB, EVHTTP_WRITE_CB, EVHTTP_ERROR_CB, Evcon); /*If There ' s still data pending, process it next time through the * loop. Don ' t do it now; That could get recusive. */    if(Evbuffer_get_length (Bufferevent_get_input (evcon->Bufev)))  {Event_deferred_cb_schedule (Get_deferred_queue (Evcon),&evcon->READ_MORE_DEFERRED_CB); }}

As you can see, the read events of FD are added to the event loop.

Finally comb the next read event invocation process:

1. A read event occurred on FD

2. BUFFEREVENT_READCB

3. EVHTTP_READ_CB

4. Evhttp_connection_done

5. Evhttp_handle_request

6. Call the user-defined evhttp callback function

About the flow of data

When a read event occurs on the FD, the data on the FD is first read into the Evhttp_connection bufferevent, and then the data in the bufferevent is read into the input buffer of the evhttp_request.

When we use evhttp_send_reply to send data, the data is first written to the evhttp_request output buffer, then to the bufferevent of evhttp_connection, and the output buffer to the FD is written last.

Libevent (13) Evhttp Event Processing flow

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.