Use of libevent in asynchronous socket

Source: Internet
Author: User
Tags socket error

When learning how to use libevent.

Example 1:

Libevent_echosrv1.c
/** Libevent echo server example. */# include
 
  
# Include
  
   
# Include
   
    
/* For inet_ntoa. */# include/* required by event. H. */# include
    
     
# Include
     
      
# Include
      
        # Include
       
         # Include
        
          # Include
         
           # Include
          
            # Include
           
             /* Libevent. */# include
            
              /* Port to listen on. */# define server_port 5555/*** this structure is the specified client data. In this example, only the read event object is specified.
             
*/ StructClient { StructEvent ev_read;};/*** set a socket to non-blocking mode */ IntSetnonblock ( IntFD ){ IntFlags; flags = fcntl (FD, f_getfl ); If(Flags return flags; flags | = o_nonblock; If(Fcntl (FD, f_setfl, flags) Return-1; Return0;}/*** this function is called by libevent when the client socket is readable */ VoidOn_read ( IntFD, ShortEv, Void* Arg ){ StructClient * client = ( StructClient *) ARG; u_char Buf [8196]; IntLen, WLEN; Len = read (FD, Buf, Sizeof(BUF )); If(LEN = 0) {/* disconnect the client, remove the read event and release the client data structure */printf ("client disconnected. /n "); close (FD); event_del (& client-> ev_read); free (client ); Return;} Else If(LEN ev_read); free (client ); Return;}

/* For convenience, we directly write the data back to the client. Generally, we cannot do this in non-blocking applications. * we should put the data in the queue and write it back to the client when the event can be written. */WLEN = write (FD, Buf, Len ); If(WLEN voidon_accept ( IntFD, ShortEv, Void* Arg ){ IntClient_fd; StructSockaddr_in client_addr; socklen_t client_len = Sizeof(Client_addr ); StructClient * client;/* accept new connections */client_fd = accept (FD ,( StructSockaddr *) & client_addr, & client_len ); If(Client_fd =-1) {warn ("Accept failed "); Return;}/* Set the client socket to non-blocking mode. */ If(Setnonblock (client_fd) sizeof (* client )); If(Client = NULL) Err (1, "malloc failed");/* sets read events. libevent calls the on_read function when the client socket is readable. * We will also constantly respond to read events, so we do not need to add read events again during each read. */Event_set (& client-> ev_read, client_fd, ev_read | ev_persist, on_read, client);/* The set event is not activated. Use the Add event to activate it. */Event_add (& client-> ev_read, null); printf ("accepted connection from % s/n", inet_ntoa (client_addr.sin_addr ));} IntMain ( IntArgc, Char** Argv ){ IntListen_fd; StructSockaddr_in listen_addr; IntReuseaddr_on = 1;/* event object for accepting connection requests. */ StructEvent ev_accept;/* initialize libevent. */event_init ();/* Create the socket we listen. */Listen_fd = socket (af_inet, sock_stream, 0 ); If(Listen_fd if (setsockopt (listen_fd, sol_socket, so_reuseaddr, & reuseaddr_on, Sizeof(Reuseaddr_on) =-1) Err (1, "setsockopt failed"); memset (& listen_addr, 0, Sizeof(Listen_addr); listen_addr.sin_family = af_inet; listen_addr.sin_addr.s_addr = inaddr_any; listen_addr.sin_port = htons (server_port ); If(BIND (listen_fd ,( StructSockaddr *) & listen_addr, Sizeof(Listen_addr) if (Listen (listen_fd, 5) if (setnonblock (listen_fd) return 0 ;}
 
 
Example 2:
/** Libevent echo server example. */# include
 
  
# Include
  
   
# Include
   
    
/* For inet_ntoa. */# include/* required by event. H. */# include
    
     
# Include
     
      
# Include
      
        # Include
       
         # Include
        
          # Include
         
           # Include
          
            # Include
           
             /* Easy sensible linked lists. */# include "queue. H"/* libevent. */# include
            
              /* Port to listen on. */# define server_port 5555/* length of each buffer in the buffer queue. also becomes the amount * of data we try to read per call to read (2 ). */# define buflen 1024 /**
             
* In event-based programming, we need a queue to store the data to be written,
* Data can be written only when libevent notifies us that data can be written. This simple Buffer Queue is used
* Tailq in queue. h to write data. */ StructBufferq {/* the buffer. */u_char * Buf;/* the length of BUF .*/ IntLen;/* The start offset of the buffer written this time. */ IntOffset;/* linked list structure. */Tailq_entry (bufferq) Entries ;};/*** the specified customer data structure, which also contains a column of user pointers. ** In an event-based program, you usually need to save some state information objects for each customer. */ StructClient {/* event object. We need two event objects, one for reading events and the other for writing Event Notifications. */ StructEvent ev_read; StructEvent ev_write;/* This is a data queue and will be written to this client. We can only wait until the libevent tells us that this socket is ready for writing,
* To write data. */Tailq_head (, bufferq) writeq ;};/*** set the socket to non-blocking mode. */ IntSetnonblock ( IntFD ){ IntFlags; flags = fcntl (FD, f_getfl ); If(Flags return flags; flags | = o_nonblock; If(Fcntl (FD, f_setfl, flags) Return-1; Return0;}/*** when the client socket is readable, libevent calls this function. */ VoidOn_read ( IntFD, ShortEv, Void* Arg ){ StructClient * client = ( StructClient *) ARG; StructBufferq * bufferq; u_char * Buf; IntLen;/* because we need to receive notifications in writeable tasks, we need to allocate a read buffer,
* Put It In The write queue of the customer data object. */Buf = malloc (buflen ); If(BUF = NULL) Err (1, "malloc failed"); Len = read (FD, Buf, buflen ); If(LEN = 0) {/* the client is disconnected. Here, the read event is removed and the customer data structure is released. */Printf ("client disconnected./N"); close (FD); event_del (& client-> ev_read); free (client ); Return;} Else If(LEN ev_read); free (client ); Return;}/* We can't just write the buffer back, because we need to respond to the libevent writable event when it can be written,
* Place the buffer zone in the write queue in the customer data structure and arrange a writable event. */Bufferq = calloc (1, Sizeof(* Bufferq )); If(Bufferq = NULL) Err (1, "malloc faild"); bufferq-> Buf = Buf; bufferq-> Len = Len; bufferq-> offset = 0; tailq_insert_tail (& client-> writeq, bufferq, entries);/* Add a writable Event Notification because we have data that needs to be written back to the client. */Event_add (& client-> ev_write, null);}/*** libevent calls this function when the client socket is ready for writing.
*/ VoidOn_write ( IntFD, ShortEv, Void* Arg ){ StructClient * client = ( StructClient *) ARG; StructBufferq * bufferq; IntLen;/* remove the first element from the write queue. We may no longer need to test whether the write queue is empty, but check that the returned value is not null. */Bufferq = tailq_first (& client-> writeq ); If(Bufferq = NULL) Return;/* Write the data in the buffer. Some of the buffer may have been written before, so only the remaining bytes are written. */Len = bufferq-> len-bufferq-> offset; Len = write (FD, bufferq-> BUF + bufferq-> offset, bufferq-> len-bufferq-> offset ); If(LEN =-1 ){ If(Errno = eintr | errno = eagain) {/* The write operation is interrupted by a signal, or we cannot write data. Adjust it and return it. */Event_add (& client-> ev_write, null ); Return;} Else{/* Some other socket errors occur. Exit. */Err (1, "write ");}} Else If(Bufferq-> Offset + Len) {/* not all data is written. Update the written offset and adjust the write event. */Bufferq-> Offset + = Len; event_add (& client-> ev_write, null ); Return;}/* The data has been completely written. Remove the buffer from the write queue. */Tailq_remove (& client-> writeq, bufferq, entries); free (bufferq-> BUF); free (bufferq );} /*** when a connection request is ready to be accepted, libevent calls this function. */ VoidOn_accept ( IntFD, ShortEv, Void* Arg ){ IntClient_fd; StructSockaddr_in client_addr; socklen_t client_len = Sizeof(Client_addr ); StructClient * client;/* receives the new connection request. */Client_fd = accept (FD ,( StructSockaddr *) & client_addr, & client_len ); If(Client_fd =-1) {warn ("Accept failed "); Return;}/* Set the client socket to non-blocking mode. */ If(Setnonblock (client_fd) sizeof (* client )); If(Client = NULL) Err (1, "malloc failed");/* sets read events. When the client socket is readable, libevent calls the on_read () function.
* We also constantly construct readable events, so we no longer need to add read events to each read. */Event_set (& client-> ev_read, client_fd, ev_read | ev_persist, on_read, client);/* The set event is not activated. Add an event to activate it. */Event_add (& client-> ev_read, null);/* Create a write event, but do not add it before we have data to be writable. */Event_set (& client-> ev_write, client_fd, ev_write, on_write, client);/* initialize the client write queue. */Tailq_init (& client-> writeq); printf ("accepted connection from % s/n", inet_ntoa (client_addr.sin_addr ));} IntMain ( IntArgc, Char** Argv ){ IntListen_fd; StructSockaddr_in listen_addr; IntReuseaddr_on = 1;/* accept event object of socket. */ StructEvent ev_accept;/* initialize libevent. */event_init ();/* create our listening socket. This is largely boiler plate * code that I'll abstract away in the future. */listen_fd = socket (af_inet, sock_stream, 0 ); If(Listen_fd if (setsockopt (listen_fd, sol_socket, so_reuseaddr, & reuseaddr_on, Sizeof(Reuseaddr_on) =-1) Err (1, "setsockopt failed"); memset (& listen_addr, 0, Sizeof(Listen_addr); listen_addr.sin_family = af_inet; listen_addr.sin_addr.s_addr = inaddr_any; listen_addr.sin_port = htons (server_port ); If(BIND (listen_fd ,( StructSockaddr *) & listen_addr, Sizeof(Listen_addr) if (Listen (listen_fd, 5) if (setnonblock (listen_fd) return 0 ;}
 
Example 3:
Libevent_echosrv_buffered.c
/** Libevent echo server example using buffered events. */# include
 
  
# Include
  
   
# Include
   
    
# Include/* required by event. H. */# include
    
     
# Include
     
      
# Include
      
        # Include
       
         # Include
        
          # Include
         
           # Include
          
            # Include
           
             /* Libevent. */# include
            
              /* Port to listen on. */# define server_port 5555 /**
             
* Specify the structure of user data, which also contains a column of user pointers. */ StructClient {/* client socket */ IntFD;/* this customer's bufferedevent object. */ StructBufferevent * buf_ev;};/*** sets a socket to non-blocking mode. */ IntSetnonblock ( IntFD ){ IntFlags; flags = fcntl (FD, f_getfl ); If(Flags return flags; flags | = o_nonblock; If(Fcntl (FD, f_setfl, flags) Return-1; Return0;}/*** when data is readable, libevent calls this function */ VoidBuffered_on_read ( StructBufferevent * Bev, Void* Arg) {/* write-back buffer. Note that bufferevent_write_buffer will gradually send the input data
* When we call it, it takes effect. */Bufferevent_write_buffer (BEV, Bev-> input);}/*** when the write buffer is 0, libevent calls this function. We wrote this function only because it is required by libevent, but we didn't use it. */ VoidBuffered_on_write ( StructBufferevent * Bev, Void* Arg) {}/*** when the basic socket descriptor is incorrect, libevent will call this function. */ VoidBuffered_on_error ( StructBufferevent * Bev, ShortWhat, Void* Arg ){ StructClient * client = ( StructClient *) ARG; If(What & evbuffer_eof) {/* the client is disconnected. Here, the read event is removed and the customer data structure is released. */Printf ("client disconnected./N ");} Else{Warn ("client socket error, disconnecting. /n ");} bufferevent_free (client-> buf_ev); close (client-> FD); free (client );} /*** when a connection request is ready to be accepted, this function will be called by libevent. */ VoidOn_accept ( IntFD, ShortEv, Void* Arg ){ IntClient_fd; StructSockaddr_in client_addr; socklen_t client_len = Sizeof(Client_addr ); StructClient * client; client_fd = accept (FD ,( StructSockaddr *) & client_addr, & client_len ); If(Client_fd return;}/* set the client socket to non-blocking mode. */ If(Setnonblock (client_fd) sizeof (* client )); If(Client = NULL) Err (1, "malloc failed"); client-> FD = client_fd;/* Create a buffered event. *
* The first parameter is the file descriptor that causes the event. Here is the client socket. *
* The second parameter is a callback function. It is called when the data has been read by the socket and is valid for the program. *
* The third parameter is a callback function. When the write buffer reaches the minimum value, it is called.
* This usually means that when the write buffer length is 0, this callback function will be called.
* It must be defined, but you can do nothing in this callback function. *
* The fourth parameter is a callback function, which is called when a socket error occurs.
* Here you can detect client disconnection or other errors. *
* The Fifth parameter is used to store a parameter that will be passed to each callback function. Here we store customer data objects. */Client-> buf_ev = bufferevent_new (client_fd, buffered_on_read, buffered_on_write, buffered_on_error, client);/* It must be valid before the callback function is called. */Bufferevent_enable (client-> buf_ev, ev_read); printf ("accepted connection from % s/n", inet_ntoa (client_addr.sin_addr ));} IntMain ( IntArgc, Char** Argv ){ IntListen_fd; StructSockaddr_in listen_addr; StructEvent ev_accept; IntReuseaddr_on;/* initialize libevent. */event_init ();/* create our listening socket. */Listen_fd = socket (af_inet, sock_stream, 0 ); If(Listen_fd sizeof (listen_addr); listen_addr.sin_family = af_inet; region = inaddr_any; listen_addr.sin_port = htons (server_port ); If(BIND (listen_fd ,( StructSockaddr *) & listen_addr, Sizeof(Listen_addr) if (Listen (listen_fd, 5) sizeof (reuseaddr_on);/* sets the socket to non-blocking mode, which is required when programming with libevent. */ If(Setnonblock (listen_fd) return 0 ;}
 
Note:
I think the second example is very useful because we can integrate the memory pool on the server side. However, the second example only considers the queue during write,
When reading data, what should I do if I fail to read all the data at one time? In fact, it can be processed like writing, that is, the read offset under the record.

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.