Use the libevent library to develop network programs

Source: Internet
Author: User
Tags doxygen

 

[Overview]
Libevent is an event-triggered network library. It is applicable to Windows, Linux, BSD, and other platforms. It uses select, epoll,

Kqueue and other systems call the management event mechanism. The famous distributed cache software memcached is also libevent based, and libevent is

It can be used on a cross-platform basis, and it also seems to have extraordinary performance according to the statistics published on the official libevent website.

 

Basic functions]
1. event_init () event_base_new ()
  Before using the event API, you must use event_init () or event_base_new () for initialization. Note that it does not support multithreading.

Shao.
  Event_base_new () can also be initialized. The mutex lock can be used for multithreading, Which is thread-safe.

2. event_dispatch () event_base_dispatch ()
  To handle events, the application must call event_dispatch (). This function is returned only when an error occurs.

Take over event. event_base_dispatch () with event_base_new, thread security.

3. event_set () event_base_set ()
Event_set (struct event * eV, int FD, short event, void (* fN) (INT, short, void *), void * Arg );
Used to generate the event struct eV for event_add () and event_del (). The event driver will call void (* fN) (INT,

In the short, void *) function specified by FN, and pass three parameters: INT: file descriptor, short: event type, void *: Other parameters by ARG

Specify the parameter. The callback function in the initialization event struct variable is required by the program caller.
Parameters:
Int FD specifies the file descriptor to be monitored,

Short event can be ev_read, ev_write or ev_read | ev_write indicates that the file can be read and written without interruption.

The FN function will be called and passed to three variables:

Int FD: file descriptor of the trigger event.

Short event: Type of the event to be triggered: ev_timeout, ev_signal, ev_read, or ev_write.

Void *: The variable specified by the ARG parameter.

In addition, duplicate registration events will generate duplicate Event Notifications. ev_persist can prevent registered events from being deleted after they are executed.

To call event_del () to delete.

After the struct is initialized, it can be reused by event_add () and event_del () without changing the content.

After a struct is added by event_add (), the content of the struct must be kept until the event is executed and exited or event_del () is called to delete the event.

It is not allowed to register this struct variable for repeated use after the event. Each descriptor requires a separate event struct variable.

For the thread security version, use event_base_set in combination with event_base_new.
Int event_base_set(Struct event_base *,Struct event *)  
Associate a different event base with an event.
Parameters:
 EBThe event Base
 EVThe event

4. event_add ()
The event_add () function executes events configured through event_set () when the event matches or times out (if a time-out is set.
The event struct variable must have been initialized with event_set () and cannot be initialized by calling event_set () again before the event is deleted.

If the event times out, the old timeout will be replaced by the new timeout.

5. event_del ()
The event_del () function cancels the event specified by the event struct. If the event has been executed or is not registered (it is not stored in the event chain table.

), This function does not play any role.
6. Time timer Series
Evtimer_set (), evtimer_add (), evtimer_del (), evtimer_initialized () evtimer_pending (), and other functions

() Is used to set scheduled or time-out operations. In these functions, the file descriptor is-1, and the event type is ev_timeout.
7. Signal Series
Functions such as signal_set (), signal_add (), signal_del (), signal_initialized (), and signal_pending () are omitted,

The event type is ev_signal. That means that the ev_persist is added to signal_set.
To avoid signal competition, event API provides two variables: event_sigcb and event_gotsig. Handle settings for a certain signal.

Event_gotsig indicates that the signal is received. The application sets event_sigcb as a callback function. When the signal handle sets event_gotsig

Then, the event_dispatch function executes the callback function to process the received signal. When no event is registered, the callback function returns 1. The callback function

You can return-1 to indicate an error. This will cause event_dispatch () to end. The error code is eintr.
8. event_pending
Event_pending
Event_pending () is used to check whether the event specified by the event struct variable is in the waiting state. If ev_timeout is set, and

If the TV struct pointer variable is not null, the event termination time is returned by TV.
9. event_initialized
   Event_initialized () is used to check whether the event struct variable has been initialized.
[Sample Code]
--------------------------------- Start ---------------------------------------
# Ifdef Win32
# Include <winsock2.h>
# Include <windows. h>
# Include <Io. h>
# Include <fcntl. h>
# Endif

# Include "event-config.h"

# Ifdef _ event ___ func __
# DEFINE _ FUNC _ event ___ func __
# Endif //

# If 0
# Include <sys/types. h>
# Include <sys/STAT. h>
# Ifdef _ event_have_sys_time_h
# Include <sys/time. h>
# Endif
# Include <sys/queue. h>
# Include <signal. h>
# Include <errno. h>
# Endif // If 0

# Ifdef _ event_have_sys_time_h
# Include <sys/time. h>
# Endif

# Include <sys/types. h>
# Include <sys/STAT. h>
# Include <sys/queue. h>

# Ifndef Win32
# Include <sys/socket. h>
# Include <sys/Wait. H>
# Include <signal. h>
# Include <unistd. h>
# Include <netdb. h>
# Endif

# Include <fcntl. h>
# Include <signal. h>
# Include <stdlib. h>
# Include <stdio. h>
# Include <string. h>
# Include <errno. h>
# Include <assert. h>
# Include <ctype. h>

# Include <event2/event. h>
# Include "event2/event_struct.h"
# Include <event2/event_compat.h>
# Include "event2/Tag. H"
# Include <event2/DNS. h>
# Include <event2/dns_compat.h>
# Include <event2/bufferevent. h>
# Include "event2/bufferevent_struct.h"
# Include <event2/buffer. h>
# Include "event2/buffer_compat.h"
# Include <event2/thread. h>
# Include "event-internal.h"
# Include <event2/util. h>
# Include "log-internal.h"
// # Include "event-config.h"
# Include <iocp-internal.h>

//// // Key code segment
# Ifdef Win32
# Define write (FD, Buf, Len) Send (FD), (BUF), (LEN), 0)
# Define read (FD, Buf, Len) Recv (FD), (BUF), (LEN), 0)
# Endif

//; "../Libevent/include/WIN32-Code"; ../libevent/include/compat; ../libevent/include
# Ifdef Win32
# Pragma comment (Lib, "ws2_32.lib ")
# Pragma comment (Lib, "../libevent/lib/libevent. lib ")
# Endif // Win32

Static void simple_read_cb (evutil_socket_t FD, short event, void * Arg );
Static int cleanup_test (void );
// Int pair [2];

# Define test1_str "Test 1 string"
Typedef struct basic_test_data {
 Struct event_base * base;
 Int pair [2];

 Void (* legacy_test_fn) (void );

 Void * setup_data;
} Basic_test_data;

Struct basic_test_data * g_data = NULL;
Int g_spair [2] = {-1,-1 };

Static void * basic_test_setup ()
{
 Struct event_base * base = NULL;
 // Make socket pair for test
 If (evutil_socketpair (af_unix, sock_stream, 0, g_spair) =-1 ){
  Fprintf (stderr, "% s: socketpair \ n", "basic_test_setup ");
  Exit (1 );
 }

 If (evutil_make_socket_nonblocking (g_spair [0]) =-1 ){
  Fprintf (stderr, "fcntl (o_nonblock )");
  Exit (1 );
 }

 If (evutil_make_socket_nonblocking (g_spair [1]) =-1 ){
  Fprintf (stderr, "fcntl (o_nonblock )");
  Exit (1 );
 }

 // Event_init ()

 Base = event_base_new ();
 If (! Base)
  Exit (1 );

 // Base = event_base_new_with_config (null );
 // If (base = NULL ){
 // Event_errx (1, "% s: Unable to construct event_base", _ FUNC __);
 //Exit (1 );
 //}

 G_data = (basic_test_data *) calloc (1, sizeof (* g_data ));
 If (! G_data)
  Exit (1 );
 G_data-> base = base;
 G_data-> pair [0] = g_spair [0];
 G_data-> pair [1] = g_spair [1];

 Return g_data;

}

Static int cleanup_test (void ){
   Event_base_free (g_data-> base );
# Ifndef Win32
   Close (g_spair [0]);
   Close (g_spair [1]);
# Else
   Closehandle (handle) g_spair [0]);
   Closehandle (handle) g_spair [1]);
# Endif
   Free (g_data );
   Return (0 );
}
Int test10000main (void * PTR)
{
 Struct basic_test_data * Data = (basic_test_data *) PTR;
 Struct event EV1;

 

 Write (g_spair [0], test10000str, strlen (test10000str) + 1 );
 Shutdown (g_spair [0], 1 );
 // Write (g_spair [0], null, 0 );
 
 Event_set (& EV1, g_spair [1], ev_read, simple_read_cb, & EV1 );
 Event_base_set (data-> base, & EV1 );
 If (event_add (& EV1, null) =-1)
  Exit (1 );
 
 Event_base_dispatch (data-> base );
 // Event_base_loop (data-> base, evloop_nonblock );
 
 Return 0;

}

Int main (INT argc, char ** argv)
{

 Word wversionrequested;
 Wsadata;
 IntErr;
 Void * Env = NULL;

 Wversionrequested = makeword (2, 2 );
 Err = wsastartup (wversionrequested, & wsadata );

 Evthread_enable_lock_debuging ();
 // Initialization
 ENV = basic_test_setup ();

 Test1_main (ENV );// Simple read/write Test
 // Test2_main (ENV );// Iocp Test
 // Test3_main (ENV );  // Bufferevent Test
 Cleanup_test ();
 Return 1;
}

--------------------------------- End ---------------------------------------

 

[Evbuffer Introduction]

 Evbuffer Data Buffer
The buffer of libevent is a continuous memory area, and its data processing method (writing data and reading data) is more like

Queue operation mode: write from the back and read from the front. Evbuffer sets related pointers (one indicator) to indicate

Read location and write location. Its general structure

 

Orig_buffer points to the continuous memory area allocated by realloc, buffer points to the memory area of valid data, totallen indicates the size of the memory area pointed to by orig_buffer, and misalign indicates the offset of buffer relative to orig_buffer, off indicates the length of valid data.

 

Evbuffer Functions]

 

X. evbuffer_new
Create buffer evbuffer

X. evbuffer_read
Reads data from the file descriptor (socket handle) to the evbuffer data structure.
Int evbuffer_read(Struct evbuffer *Buffer,
 Evutil_socket_tFD,
 IntHowmuch 
 )  

Read from a file descriptor and store the result in an evbuffer.
Parameters:
 BufThe evbuffer to store the result
 FDThe file descriptor to read from
 HowmuchThe number of bytes to be read

Returns:
The number of bytes read, or-1 if an error occurred

X. evbuffer_write
Data in the evbuffer data structure is written to the file descriptor (socket handle.

Int evbuffer_write(Struct evbuffer *Buffer,
 Evutil_socket_tFD 
 )  

Write the contents of an evbuffer to a file descriptor.

The evbuffer will be drained after the bytes have been successfully written.

Parameters:
 BufferThe evbuffer to be written and drained
 FDThe file descriptor to be written

Returns:
The number of bytes written, or-1 if an error occurred

 

X. evbuffer_drain:
   This function mainly operates on some metrics. Every time you read data from the evbuffer, The libevent will

The buffer pointer moves backward, increases misalign at the same time, and reduces off, which is exactly what this function does. To put it bluntly,

This function is used to adjust the forward indicator of the buffer queue.
VoidEvbuffer_drain (struct evbuffer *, size_t)
 Remove a specified number of bytes data from the beginning of an evbuffer.
Parameters:
 BufThe evbuffer to be drained
 LenThe number of bytes to drain from the beginning of the buffer

X. evbuffer_remove:
   This function is used to copy data in evbuffer to the user space (read data ). Simply put the data memcpy,

Then call evbuffer_drain to move the relevant indicator.
IntEvbuffer_remove (struct evbuffer *, void *, size_t)
Read data from an event buffer and drain the bytes read.
Parameters:
 BufThe event buffer to be read from
 DataThe destination buffer to store the result
 DatlenThe maximum size of the destination Buffer
Returns:
The number of bytes read

X. evbuffer_add:
   This function is used to add a piece of user data to evbuffer. It is very simple, that is, first determine whether there is enough null

Idle memory. If no memory exists, call evbuffer_expand to expand the memory, and then directly memcpy and update the off indicator.

IntEvbuffer_add (struct evbuffer *, const void *, size_t)
Append data to the end of an evbuffer.
Parameters:
 BufThe event buffer to be appended
 DataPointer to the beginning of the Data Buffer
 DatlenThe number of bytes to be copied from the Data Buffer

X. evbuffer_expand:
   This function is used to expand the evbuffer capacity. Every time you write data to evbuffer, the data is written

After buffer + off, the buffer to buffer + off is used and valid data is saved.

The between orig_buffer and buffer is an invalid zone formed by reading the data moving indicator.

The evbuffer_expand extension policy is to first determine if the orig_buffer and buffer are idle

Whether the region can accommodate the added data. If yes, move the data between buffer and buffer + off

Orig_buffer and orig_buffer + off (memory overlap may occur, so here the mobile call is

Memmove), and then copy the new data to orig_buffer + off; if it cannot be accommodated, then re-

Allocate more space (realloc) and move the data. Memory expansion policy: ensure the new memory area

The minimum size is 256, and is gradually expanded by multiplying by 2 (256, 512, 1024 ,...).

 

[Sample Code]
Main Function Code. For other code, refer to the previous article.

--------------------------------- Start ---------------------------------------

Int test3_main (void * PTR)
{
 
 Struct basic_test_data * Data = (basic_test_data *) PTR;
 Struct event EV1;

 Write (g_spair [0], test10000str, strlen (test10000str) + 1 );
 Shutdown (g_spair [0], 1 );

 Event_set (& EV1, g_spair [1], ev_read, simple_evbuffer_read_cb, & EV1 );
 Event_base_set (data-> base, & EV1 );
 If (event_add (& EV1, null) =-1)
  Exit (1 );

 Event_base_dispatch (data-> base );

 Return 0;
}

Static void
Simple_evbuffer_read_cb (evutil_socket_t FD, short event, void * Arg)
{
 Char Buf [256];
 Int Len;
 Struct evbuffer * TMP = evbuffer_new ();
 Len = evbuffer_read (TMP, FD,-1 );
 

 

 If (LEN ){
  Evbuffer_remove (TMP, Buf, Len );
  Printf ("simple_read_cb FD: �uf: % s \ n", FD, Buf );
  If (event_add (ARG, null) =-1)
   Exit (1 );
 } Else {
  Printf ("simple_read_cb FD: % d connection closed \ n", FD );
 }

}

 

--------------------------------- End ---------------------------------------

 

[Other Aspects]
1. epoll in libevent uses horizontal triggering. This efficiency is still high without edge triggering and can be directly used.

Epoll can also improve performance.

2. thread security issues
If libevent is initialized with event_init, multithreading is not supported, or it is insecure due to multithreading,

Therefore, it is also restricted.
Solution 1:
Reference: http://www.cppblog.com/converse/archive/2009/01/12/71809.html
Http://it.newnew.cn/it53180.aspx
Solution 2: Use event_base_new () for initialization and mutex lock.

 

[Reference]
X. libevent Homepage
Http://monkey.org /~ Provos/libevent/
X. Official documentation
Http://monkey.org /~ Provos/libevent/doxygen-2.0.1/index.html
X. Source Code Analysis-libevent Event Processing Framework Analysis
Http://www.cppblog.com/converse/archive/2009/01/03/71040.html
X. socketpair Problems
Http://liulixiaoyao.blog.51cto.com/1361095/533469
X. Tutorial
Libevent Network Programming
Http://www.wangafu.net /~ Nickm/libevent-book/toc.html
Libevent network programming Chinese Translation
Http://blog.sina.com.cn/s/articlelist_1457448730_0_1.html
Http://blog.sina.com.cn/s/blog_56dee71a0100q2i9.html
Http://blog.sina.com.cn/s/blog_56dee71a0100qx4s.html
Others
Http://hustlg.bokee.com/6573083.html
Http://blog.csdn.net/dlmu2001/archive/2010/06/20/5682456.aspx
Http://monkey.org /~ Provos/libevent/doxygen-1.4.10/event_8h.html
X. echo server
Http://ishbits.googlecode.com/svn-

History/R5/trunk/libevent_echosrv/libevent_echosrv1.c
X. evbuffer usage
Http://www.cppblog.com/kevinlynx/archive/2008/07/16/56291.html
Http://team.eyou.com /? P = 32
X. spserver Problems
Http://code.google.com/p/spserver/
Http://iunknown.javaeye.com/blog/59804

----------------------------------------------------------------------

This article is original, reprint please indicate the source http://blog.sina.com.cn/faithfish

 

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.