I. Introduction of Libevent
Libevent is an event-triggered network library for Windows, Linux, BSD and other platforms, internal use of Select, Epoll, Kqueue and other systems call management event mechanism. Official website: http://libevent.org/
Characteristics:
Event-driven, high performance;
Lightweight, focus on the network, as the ACE is so bloated and large, only provides a simple network API encapsulation, thread pool, memory pool, recursive lock, etc. all need to implement themselves;
Open source, the code is quite refined, easy to read;
Cross-platform support for Windows, Linux, BSD and Mac OS;
Support multiple I/O multiplexing Technologies (Epoll, poll, Dev/poll, select, Kqueue, etc.), the abstraction of a multiplexed model under different operating systems, and the option to use different models to provide services through event functions;
Supports events such as I/O, timers and signals;
Adopt reactor mode;
Ii. Source Organization Structure
Although the source code of Libevent is under one layer of folder, but its codes are still quite clear, the main can be divided into header files, internal use of the header files, auxiliary functions, logs, Libevent framework, the system I/O multiplexing mechanism encapsulation, signal management, timing event management, Buffer management, basic data structures, and two utility libraries based on libevent, some of which may be a source file.
1) header File
is mainly event.h: Event macro definition, interface function declaration, the main structure of the event declaration;
2) Internal Header file
Xxx-internal.h: Internal data structures and functions are not visible to the outside, in order to achieve the purpose of information hiding;
3) Libevent Frame
Event.c:event the whole framework of code implementation;
4) Encapsulation of the system I/O multiplexing mechanism
EPOLL.C: Encapsulation of the epoll;
SELECT.C: Encapsulation of the Select;
DEVPOLL.C: Encapsulation of the dev/poll;
KQUEUE.C: Encapsulation of the kqueue;
5) Timed Event management
Min-heap.h: In fact, it is a small Gan structure with time as key;
6) Signal Management
SIGNAL.C: The processing of signal events;
7) Auxiliary function function
Evutil.h and EVUTIL.C: Some accessibility functions, including the creation of the socket pair and some time manipulation functions: Add, subtract, and compare.
8) Log
Log.h and Log.c:log log functions
9) Buffer Management
Evbuffer.c and Buffer.c:libevent to the buffer package;
10) Basic Data structure
Compat/sys Two source files: Queue.h is the implementation of Libevent basic data structure, including linked lists, doubly linked lists, queues, etc. _libevent_time.h: Some structure definitions, functions, and macro definitions for time operations;
11) Practical Network Library
HTTP and Evdns: is based on the implementation of Libevent HTTP server and asynchronous DNS query library;
Iii. examples
1. Get version
GCC Getversion.c-o getversion-levent
#include <event.h>
#include <stdio.h>
int main ()
{
const char *version = Event_get_version ();
printf ("%s\n", version);
return 0;
}
2. Timer Program
//gcc timer.c-o timer-levent
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#define N
#define Buflen
struct Timeval lasttime;
struct St_eventwithdescription
{
struct event *p_event;
int time_interval;
Char Lable[buflen];
};
static void Timeout_cb (evutil_socket_t fd, short event, void *arg)
{
struct timeval newtime, difference;
struct St_eventwithdescription *pstevent = arg;
struct Event *timeout = pstevent->p_event;
double elapsed;
Evutil_gettimeofday (&newtime, NULL);
evutil_timersub (&newtime, &lasttime, &difference);
elapsed = difference.tv_sec + (difference.tv_usec/1.0e6);
printf ("%s called at%d:%.3f seconds since my last work.\n",
(char*) pstevent->lable, (int) newtime.tv_sec, elapsed);
lasttime = newtime;
struct Timeval TV;
evutil_timerclear (&TV);
tv.tv_sec = pstevent->time_interval;
Event_add (timeout, &tv);
}
void SetParam (struct st_eventwithdescription *steventdescription,
struct Event *m_event,int time_interval,char* m_lable)
{
steventdescription->p_event = m_event;
steventdescription->time_interval = time_interval;
memset (steventdescription->lable,0,sizeof (steventdescription->lable));
memcpy (Steventdescription->lable,m_lable,strlen (m_lable) +1);
}
void Settimeintervalarr (int *arr,int N)
{
int i;
Srand (Time (NULL));
For (i=0; i<n; ++i)
{
* (arr+i) = rand ()%n + 1;
//* (arr+i) = i+1;
}
}
int main (int argc, char **argv)
{
struct event Timeout[n];
struct st_eventwithdescription stevent[n];
int time_interval[n];
int i=0;
struct Timeval TV;
struct event_base *base;
int flags = 0;
Settimeintervalarr (time_interval,n);
base = Event_base_new ();
evutil_timerclear (&TV);
For (i=0; i<n; ++i)
{
char buf[buflen]= {0};
sprintf (buf, "task%d", i+1);
SetParam (STEVENT+I,TIMEOUT+I,TIME_INTERVAL[I],BUF);
event_assign (Timeout+i, Base,-1, Flags, TIMEOUT_CB, (void*) (stevent+i));
Event_add (Timeout+i, &TV);
}
Evutil_gettimeofday (&lasttime, NULL);
Event_base_dispatch (base);
return (0);
}
3. Socket Program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <event.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
static short listenport = 8080;
static Long listenaddr = inaddr_any;//The value of any address is 0
static int maxconnections = 1024x768;
static int serversocket;
static struct event serverevent;//Create event
//No matter what platform you write the network program, you should use Nonblock to set a socket to non-blocking mode. This will ensure that your program does not have a block at least recv/send/accept/connect these operations to stop the entire Network service
int setnonblock (int fd)
{
int flags;
if (flags = FCNTL (FD, F_GETFL)) = =-1) {//To manipulate some features of the file descriptor
return-1;
}
if (Fcntl (FD, F_SETFL, Flags | O_nonblock) = =-1) {
return-1;
}
return 0;
}
//This function is called by Libevent when the client socket is readable
void Serverread (int fd, short ev, void *arg)
{
struct Client *client = (struct client *) arg;
U_char buf[8196];
int Len, Wlen;
//The file referred to by the parameter FD will be transferred count bytes to the memory indicated by the BUF pointer
len = Read (fd, buf, sizeof (BUF));
if (len = = 0) {
/ * Client Disconnects, removes read events here and frees the customer data structure * /
printf ("disconnected\n");
Close (FD);
Event_del (&serverevent);
Free (client);
return;
} else if (Len < 0) {
/ * There are other errors, close the socket here, remove the event, and release the customer data structure * /
printf ("Socket fail%s\n", Strerror (errno));
Close (FD);
Event_del (&serverevent);
Free (client);
return;
}
/*
for simplicity, we write the data back to the client directly. Usually we can't do this in a non-blocking application,
we should put the data in the queue and wait for the writable event to be written back to the client.
error when using multiple terminals for socket connection socket fail bad file descriptor
*/
Wlen = Write (fd, buf, Len);
if (Wlen < len) {
printf ("Not all data write client\n");
}
return;
}
/*
When a connection request is ready to be accepted, the function is called by Libevent and passed to three variables:
int FD: The file descriptor that triggered the event.
Short event: The type of the triggering event ev_timeout,ev_signal, Ev_read, or Ev_write.
void*: The variable specified by the arg parameter.
*/
void serveraccept (int fd, short ev, void *arg)
{
int cfd;
struct sockaddr_in addr;
socklen_t addrlen = sizeof (addr);
int yes = 1;
int retval;
//will obtain the connection information from the connection request queue, create a new socket, and return the file descriptor for the socket.
//The newly created socket is used for communication between the server and the client, and the original socket is still in the listening state.
//The first parameter of the function specifies a stream socket in the listening state
cfd = Accept (fd, (struct sockaddr *) &addr, &addrlen);
if (cfd = =-1) {
printf ("Accept (): Can not accept client connection");
return;
}
if (setnonblock (cfd) = =-1) {
Close (CFD);
return;
}
//SET options associated with a socket
//Parameter two ipproto_tcp:tcp option
//Parameter three tcp_nodelay do not use the Nagle algorithm to choose to send data immediately instead of waiting for more data to be generated and then sent again
//More parameters Tcp_nodelay and Tcp_cork
//Parameter four the value of the new option Tcp_nodelay
if (setsockopt (CFD, Ipproto_tcp, Tcp_nodelay, &yes, sizeof (yes)) = = =-1) {
printf ("setsockopt (): Tcp_nodelay%s\n", Strerror (errno));
Close (CFD);
return;
}
Event_set (&serverevent, CFD, Ev_read | Ev_persist, Serverread, NULL);
Event_add (&serverevent, NULL);
printf ("Accepted connection from%s\n", Inet_ntoa (ADDR.SIN_ADDR));
}
int newsocket (void)
{
struct sockaddr_in sa;
//socket function to create a socket that is capable of network communication.
The first parameter specifies the protocol family of the communication protocol used by the application, and for the TCP/IP protocol family, the parameter is af_inet;
///The second parameter specifies the type of socket to be created
//Stream socket type is SOCK_STREAM, datagram socket type is SOCK_DGRAM, raw socket Sock_raw
the//third parameter specifies the communication protocol used by the application.
ServerSocket = socket (af_inet, sock_stream, 0);
if (ServerSocket = =-1) {
printf ("socket (): Can not create server socket\n");
return-1;
}
if (setnonblock (serversocket) = =-1) {
return-1;
}
//Empty memory data
memset (&sa, 0, sizeof (SA));
sa.sin_family = af_inet;
//htons converting an unsigned short integer value to a network byte order
Sa.sin_port = htons (listenport);
//htonl Converting unsigned long-shaped numbers of hosts into network byte order
sa.sin_addr.s_addr = htonl (listenaddr);
//(struct sockaddr*) &sa to cast SA to SOCKADDR type pointer
/*struct sockaddr
The data structure is used for the parameters of bind, connect, recvfrom, SendTo and other functions to specify the address information.
in general programming, however, it does not operate directly against this data structure, but instead uses another data structure struct that is equivalent to sockaddr sockaddr_in
sockaddr_in and sockaddr are parallel structures, and pointers to sockaddr_in structures can also point to
SOCKADD The structure of the body and replace it. In other words, you can use sockaddr_in to build the information you need,
at the end of the type conversion is possible.
*/
The //bind function is used to bind a socket to a known address
if (Bind (ServerSocket, (struct sockaddr*) &sa, sizeof (sa)) = =-1) {
Close (serversocket);
printf ("bind (): Can not bind server socket");
return-1;
}
//Execute listen after socket enters passive mode
//maxconnections The maximum length of the connection request queue, the new connection request will be rejected after the queue is full
if (Listen (ServerSocket, maxconnections) = =-1) {
printf ("Listen (): Can not listen server socket");
Close (serversocket);
return-1;
(EXT) Libevent Introduction and examples