[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