Some experience of reusing bufferevent

Source: Internet
Author: User

Read some examples of online use of bufferevent, is generally a connection to a bufferevent, connect to accept the time, to bufferevent set on the FD and corresponding callback, when the connection is broken or error occurred, Release the bufferevent.

Yesterday, when using bufferevent, a whim, prepared a Connection object pool, each connection associated with a bufferevent, and then multithreading processing connection data transmission, Each thread is a connection linked list. When connection error or close, empty the relevant state of connection and put it back in the queue.

1. Each time a new connection is accepted, remove the idle connection in the queue, set the relevant FD and return

1 BOOLconnection::setupconnection (evutil_socket_t FD)2 {3M_FD =FD;4 evutil_make_socket_nonblocking (FD);5BUFFEREVENT_SETCB (M_be, Doread, NULL, Doerror, This);6 bufferevent_setfd (M_be, FD);7     if(Bufferevent_enable (M_be, ev_read| Ev_write)! =-1)8     {9m_bused =true;Ten     } One     returnm_bused; A}

2. In EVENT_CB, if you receive EOF or error, close connection

1 voidConnection::D oevent (structBufferevent *bev, ShortWhat,void*ctx)2 {3Connection *pconn = (connection*) CTX;4     if(What & (bev_event_error|bev_event_eof))5     {6Pconn->closeconnection ();7     }8     ......9}
voidconnection::closeconnection () {//because CloseConnection is called in the event fallback of the libevent thread, the direct//BUFFEREVENT_SETFD will automatically drop the previous event to delete.//bufferevent_disable (m_be, Ev_read | Ev_write);BUFFEREVENT_SETFD (M_be,-1);    Evutil_closesocket (M_FD); M_FD= -1; //when the BUFFEREVENT_SETFD setting FD is-1, the write and read event will not be//Add to Event_base, if the number of event listeners in Event_base is 0,//Event_base_loop will exit, causing the libevent thread to end, so here re-manually//turn on the Write,read eventBufferevent_enable (M_be, ev_read|ev_write); M_bused=false;}

3. When there is a new client accept, re-call Setupconnection to establish a new connection connection.

It is generally known that bufferevent has a management to send and receive data of the sharp weapon evbuffer, the general sending data is called Bufferevent_write, the data is written to send the Evbuffer, the socket can send data when the data is sent, Read is also the case, the data in the socket is read into the received Evbuffer, the call READ_CB notify the user data readable. So, the problem is, in a series of bufferevent interfaces called in CloseConnection, the data for these two evbuffer are not emptied, which results in a re-setupconnection. Bufferevent will have a portion of the previous FD data, causing the new FD to be disturbed when it handles receiving and transmitting data.

The first reaction must be to erase the data in the Evbuffer, and then think of the Evbuffer_drain interface to clean up the data. Clean receive evbuffer time, no problem, and generally after the socket disconnects or errors, will also be received in the Evbuffer data are read out to deal with. But in the cleanup send Evbuffer, found Evbuffer_drain failure, and then turned down the libevent source:

intEvbuffer_drain (structEvbuffer *buf, size_t len) {    structEvbuffer_chain *chain, *Next;    size_t remaining, Old_len; intresult =0;    Evbuffer_lock (BUF); Old_len= buf->Total_len; if(Old_len = =0)        GotoDone ; In this place, direct goto done.if(buf->Freeze_start) {Result= -1; GotoDone }        ....}

Buf->freeze_start was 1 and ended directly, and did not empty the evbuffer. Refer to the http://blog.csdn.net/zhwei_87/article/details/ 43304383 of the source analysis found that the bufferevent send Evbuffer only when the real data is sent unfreeze start, the other time is freeze (so only allow you to write new data to send Evbuffer, Because writing is written to end, drain is handled by Libevent himself), which is also very well understood, because the data sent in the Evbuffer is not allowed to drain start (the head of the data is to send), about start and end, is because Evbuffer is a linked list structure that stores the data that is sent. The code below, this function is libevent really used to send the data back, the user's return to this function will not be executed at the end.

Static voidBUFFEREVENT_WRITECB (evutil_socket_t fd, Short Event,void*Arg) {    structBufferevent *bufev =Arg; structBufferevent_private *bufev_p =evutil_upcast (Bufev,structBufferevent_private, Bev); intres =0;  Shortwhat =bev_event_writing; intConnected =0; ev_ssize_t Atmost= -1;    _bufferevent_incref_and_lock (Bufev); if(Event==ev_timeout) {        /*Note that we are only check for event==ev_timeout. If * event==ev_timeout| Ev_write, we can safely ignore the * timeout, since a read has occurred*/ What|=bev_event_timeout; Gotoerror; }    if(bufev_p->connecting) {        intc =evutil_socket_finished_connecting (FD); /*we need to fake the error if the connection is refused * immediately-usually connection to localhost on BS D*/        if(bufev_p->connection_refused) {bufev_p->connection_refused =0; C= -1; }        if(c = =0)            GotoDone ; Bufev_p->connecting =0; if(C <0) {Event_del (&bufev->ev_write); Event_del (&bufev->ev_read);            _BUFFEREVENT_RUN_EVENTCB (Bufev, bev_event_error); GotoDone ; } Else{Connected=1; #ifdef WIN32if(Bev_is_async (Bufev)) {Event_del (&bufev->ev_write);                Bufferevent_async_set_connected (Bufev);                _BUFFEREVENT_RUN_EVENTCB (Bufev, bev_event_connected); GotoDone ; }#endif_BUFFEREVENT_RUN_EVENTCB (Bufev, bev_event_connected); if(! (bufev->enabled & ev_write) | |bufev_p-write_suspended) {Event_del (&bufev->ev_write); GotoDone ; } }} atmost=_bufferevent_get_write_max (bufev_p); if(bufev_p->write_suspended)GotoDone ; //this place will unfree out and send the data    if(Evbuffer_get_length (bufev->output)) {Evbuffer_unfreeze (Bufev->output,1); Res= Evbuffer_write_atmost (bufev->output, FD, atmost); Evbuffer_freeze (Bufev->output,1); if(res = =-1) {            intErr =Evutil_socket_geterror (FD); if(Evutil_err_rw_retriable (ERR))Gotoreschedule; what|=Bev_event_error; } Else if(res = =0) {            /*EOF Case XXXX Actually, a 0 on the write doesn ' t indicate an EOF.             An econnreset might is more typical. */ What|=bev_event_eof; }        if(Res <=0)            Gotoerror;    _bufferevent_decrement_write_buckets (bufev_p, RES); }    if(Evbuffer_get_length (bufev->output) = =0) {Event_del (&bufev->ev_write); }    /** Invoke The user callback if our buffer was drained or below the * low watermark. */    if(res | |!connected) &&Evbuffer_get_length (Bufev->output) <= bufev->Wm_write.low)    {_BUFFEREVENT_RUN_WRITECB (BUFEV); }    GotoDone ; reschedule:if(Evbuffer_get_length (bufev->output) = =0) {Event_del (&bufev->ev_write); }    GotoDone ; error:bufferevent_disable (Bufev, ev_write); _BUFFEREVENT_RUN_EVENTCB (Bufev, what); Done: _bufferevent_decref_and_unlock (Bufev);}
View Code

Therefore, if you need to empty the data in the Bufferevent send Evbuffer, you must manually call Evbuffer_unfreeze to unfreeze the start to drain. Of course, the general Bufferevent_write is done in other threads, so make sure that there are no threads in the drain when bufferevent_write, I do not deal with multi-threaded write this block, or go to drain directly at the setupconnection.

voidconnection::closeconnection () {//The output evbuffer needs to be unfreeze firstEvbuffer_unfreeze (Bufferevent_get_output (M_be),1); if(Evbuffer_drain (Bufferevent_get_input (M_be), Evbuffer_get_length (Bufferevent_get_input (M_be)))) {... } size_t Length=evbuffer_get_length (Bufferevent_get_output (m_be)); if(Evbuffer_drain (Bufferevent_get_output (m_be), length)) {...} BUFFEREVENT_SETFD (M_be,-1);    Evutil_closesocket (M_FD); M_FD= -1; Bufferevent_enable (M_be, Ev_read|ev_write); M_bused=false;}

So bufferevent can be reused, do not know if this is not the right way, a bit of trouble, or redistribution bufferevent come convenient feeling.

Some experience of reusing bufferevent

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.