Linux expoll model and linuxexpoll Model

Source: Internet
Author: User
Tags set socket

[Switch] linux expoll model and linuxexpoll Model

Address: http://www.cnblogs.com/venow/archive/2012/11/30/2790031.html

Definition:

  Epoll is a poll improved by the Linux kernel to handle a large number of handles. It is an enhanced version of the multi-channel multiplexing I/O interface select/poll in Linux, it can significantly reduce the CPU usage of the system when the program is active in a large number of concurrent connections. Because it will reuse the file descriptor set to pass the results, instead of forcing the developer to re-Prepare the file descriptor set to be listened before each wait event. Another reason is that when obtaining the event, it does not need to traverse the entire listener descriptor set, as long as it traverses the descriptor set that is asynchronously awakened by kernel IO events and is added to the Ready queue. In addition to Level Triggered, epoll also provides Edge Triggered, which makes it possible for user space programs to cache IO states, reduce epoll_wait/epoll_pwait calls and provide application efficiency.

Working Method:

LT(Level triggered): horizontal trigger, default mode. Both block and no-block socket are supported. In this way, the kernel tells us whether a file descriptor is ready. If yes, you can perform IO operations on the ready fd. If you do not perform any operation, the kernel will continue to inform you, so the possibility of programming errors in this mode is small. The traditional select \ poll model is representative of this model.

  ET(Edge-triggered): edge-triggered, high-speed mode, only supports no-block socket. In this mode, when the descriptor is never ready, the kernel tells you through epoll. Then it will assume that you know that the file descriptor is ready and will not send more ready notifications for that descriptor, until you do some operations, the file descriptor is no longer in the ready state (for example, you are sending, accepting, or receiving requests, or an EWOULDBLOCK error occurs when the number of received data is less than a certain amount ). However, note that if I/O operations are not performed on this fs until it is ready again, the kernel will not send more notifications.

 Differences: LT events will not be discarded, but will keep you informed as long as there is data in the read buffer for users to read. ET is only notified when an event occurs.

Usage:

1. int epoll_create (int size)

Create an epoll handle. The parameter size is used to tell the number of kernel listeners.

2. int epoll_ctl (int epfd, int op, int fd, struct epoll_event * event)

Epoll event registration function,

The epfd parameter is the epoll handle;

The op parameter indicates the action, which is represented by three macros: EPOLL_CTL_ADD (register a new fd to epfd), EPOLL_CTL_MOD (modify the listening event of the registered fd ), EPOLL_CTL_DEL (delete an fd from epfd );

The fd parameter is the identifier to be monitored;

The event parameter tells the kernel the event to be monitored. The event structure is as follows:

struct epoll_event {  __uint32_t events;  /* Epoll events */  epoll_data_t data;  /* User data variable */};

The events can use the following macro sets:

EPOLLIN: indicates that the corresponding file descriptor can be read (including the normal shutdown of the Peer SOCKET)

EPOLLOUT: indicates that the corresponding file descriptor can be written.

EPOLLPRI: indicates that the corresponding file descriptor has an urgent readable data (Here it should indicate that out-of-band data has arrived)

EPOLLERR: indicates that the corresponding file descriptor is incorrect.

EPOLLHUP: indicates that the corresponding file descriptor is hung up;

EPOLLET: Set EPOLL to Edge Triggered mode, which is relative to Level Triggered.

EPOLLONESHOT: only listens for an event once. After listening for this event, if you want to continue listening for this socket, you need to add this socket to the EPOLL queue again.

3. int epoll_wait (int epfd, struct epoll_event * events, int maxevents, int timeout)

Wait for event generation, similar to the select () call. The events parameter is used to get the event set from the kernel. maxevents tells us how big the kernel events is. The value of maxevents cannot be greater than the size when epoll_create () is created. The timeout parameter is the timeout time (in milliseconds, 0 will be returned immediately,-1 will be uncertain, or it is said to be permanently blocked ). This function returns the number of events to be processed. If 0 is returned, the Operation has timed out.

Example:

Next, I will introduce a simple program written by someone else in google code. Svn path: http://sechat.googlecode.com/svn/trunk/

This program is a simple chat room program written in Linux C ++. The server is mainly implemented using the epoll model and supports high concurrency. I tested that when 10000 clients connect to the server, the processing time of the server is less than 1 second. Of course, after the client connects to the server, it only receives the welcome message from the server and does not communicate with the server. Although the program is relatively simple, we also provide an idea when considering high server concurrency. In this program, I have killed all debugging information and some epoll-independent information, and added necessary comments, which should be easy to understand.

The program contains two header files and three cpp files. In the three cpp files, each cpp file is an application, server. cpp: server program, client. cpp: a single client program, tester. cpp: simulates high concurrency and enables 10000 clients to connect to the server.

The utils. h header file contains a function that sets socket as a non-blocking function, as shown below:

int setnonblocking(int sockfd){    CHK(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK));    return 0;}

In the local. h header file, some constant definitions and function declarations are as follows:

# Define BUF_SIZE 1024 // default buffer # define SERVER_PORT 44444 // listening port # define SERVER_HOST "192.168.34.15" // server IP address # define EPOLL_RUN_TIMEOUT-1 // epoll timeout # define EPOLL_SIZE 10000 // The maximum number of clients monitored by epoll # define STR_WELCOME "Welcome to seChat! You ID is: Client # % d "# define STR_MESSAGE" Client # % d> % s "# define STR_NOONE_CONNECTED" Noone connected to server failed t you! "# Define CMD_EXIT" EXIT "// two useful macro definitions: Check and assign values and check # define CHK (eval) if (eval <0) {perror (" eval "); exit (-1) ;}# define CHK2 (res, eval) if (res = eval) <0) {perror ("eval"); exit (-1 );} // ================================================ ========================================================== ==============================/// Function Name: setnonblocking // Function Description: set socket to non-blocking // input: [in] sockfd socket identifier // output: NONE // return: 0 // =================================================== ========================================================== ========================== int setnonblocking (int sockfd );

// ================================================ ========================================================== ==============================/// Function Name: handle_message // Function Description: process each client socket // input: [in] new_fd socket identifier // output: NONE // return: the length of the data received from the client. ========================================================== ====================================== int handle_message (int new_fd );

The epoll model is implemented here in the server. cpp file, as follows:

# Include "local. h "# include" utils. h "using namespace std; // The listlist that stores the client socket descriptor <int> clients_list; int main (int argc, char * argv []) {int listener; // listen to socket struct sockaddr_in addr, their_addr; addr. sin_family = PF_INET; addr. sin_port = htons (SERVER_PORT); addr. sin_addr.s_addr = inet_addr (SERVER_HOST); socklen_t socklen; socklen = sizeof (struct sockaddr_in); static struct epoll_event ev, events [EPOLL_SIZE]; ev. events = EPOLLIN | EPOLLET; // if you are interested in reading, the char message [BUF_SIZE]; int epfd; // epoll descriptor clock_t tStart is triggered on the edge; // int client, res, epoll_events_count; CHK2 (listener, socket (PF_INET, SOCK_STREAM, 0); // initialize the listener socket setnonblocking (listener ); // set the listening socket to CHK (bind (listener, (struct sockaddr *) & addr, sizeof (addr); // bind the listening socket CHK (listen (listener, 1); // set the listener CHK2 (epfd, epoll_creat E (EPOLL_SIZE); // create an epoll Descriptor and add the listening socket to epoll ev. data. fd = listener; CHK (epoll_ctl (epfd, EPOLL_CTL_ADD, listener, & ev); while (1) {CHK2 (epoll_events_count, epoll_wait (epfd, events, EPOLL_SIZE, expiration )); tStart = clock (); for (int I = 0; I <epoll_events_count; I ++) {if (events [I]. data. fd = listener) // new connection comes. Add the connection to epoll and send the Welcome Message {CHK2 (client, accept (listener, (struct sockaddr *) & th Eir_addr, & socklen); setnonblocking (client); ev. data. fd = client; CHK (epoll_ctl (epfd, EPOLL_CTL_ADD, client, & ev); clients_list.push_back (client); // Add a new client to list bzero (message, BUF_SIZE ); res = sprintf (message, STR_WELCOME, client); CHK2 (res, send (client, message, BUF_SIZE, 0);} else {CHK2 (res, handle_message (events [I]. data. fd); // Note: epoll_ctl is not called to reset the socket event type, but you can still receive the message sent from the client} pri Ntf ("Statistics: % d events handled at: %. 2f second (s) \ n ", epoll_events_count, (double) (clock ()-tStart)/CLOCKS_PER_SEC);} close (listener); close (epfd); return 0 ;} int handle_message (int client) {char buf [BUF_SIZE], message [BUF_SIZE]; bzero (buf, BUF_SIZE); bzero (message, BUF_SIZE); int len; CHK2 (len, recv (client, buf, BUF_SIZE, 0); // accept the client information if (len = 0) // close the client or make an error, close the socket, and remove socket {CHK (c Lose (client); clients_list.remove (client);} else // send information to the client {if (clients_list.size () = 1) {CHK (send (client, STR_NOONE_CONNECTED, strlen (STR_NOONE_CONNECTED), 0); return len;} sprintf (message, STR_MESSAGE, client, buf); list <int >:: iterator it; for (it = clients_list.begin (); it! = Clients_list.end (); it ++) {if (* it! = Client) {CHK (send (* it, message, BUF_SIZE, 0) ;}} return len ;}

The tester. cpp file simulates the high concurrency of the server. Enable 10000 clients to connect to the server, as shown below:

# Include "local. h "# include" utils. h "using namespace std; char message [BUF_SIZE]; // receives the server information list <int> list_of_clients; // stores all client int res; clock_t tStart; int main (int argc, char * argv []) {int sock; struct sockaddr_in addr; addr. sin_family = PF_INET; addr. sin_port = htons (SERVER_PORT); addr. sin_addr.s_addr = inet_addr (SERVER_HOST); tStart = clock (); for (int I = 0; I <EPOLL_SIZE; I ++) // generate EPOLL_SIZE clients. Here is 1 0000, simulate high concurrency {CHK2 (sock, socket (PF_INET, SOCK_STREAM, 0); CHK (connect (sock, (struct sockaddr *) & addr, sizeof (addr )) <0); list_of_clients.push_back (sock); bzero (& message, BUF_SIZE); CHK2 (res, recv (sock, message, BUF_SIZE, 0 )); printf ("% s \ n", message) ;}list <int >:: iterator it; // remove all clients for (it = list_of_clients.begin (); it! = List_of_clients.end (); it ++) close (* it); printf ("Test passed at: %. 2f second (s) \ n ", (double) (clock ()-tStart)/CLOCKS_PER_SEC); printf (" Total server connections was: % d \ n ", EPOLL_SIZE ); return 0 ;}

I will not give the execution result of the program, but the following is a test by the Code author. It can be seen that concurrency is 10000 free of pressure.

A single client connects to the server. The client. cpp file is as follows:

# Include "local. h "# include" utils. h "using namespace std; char message [BUF_SIZE];/* process: Call fork to generate two processes. Two processes communicate with each other through pipelines. Sub-processes: Waiting for input by the customer, and the customer input information is written to the parent process through the pipeline: accept the server information and display, send the information received from the child process to the server */int main (int argc, char * argv []) {int sock, pid, pipe_fd [2], epfd; struct sockaddr_in addr; addr. sin_family = PF_INET; addr. sin_port = htons (SERVER_PORT); addr. sin_addr.s_addr = inet_addr (SERVER_HOST); static struct epoll_event ev, events [2]; ev. events = EPOLLIN | EPOLLET; // exit flag int continue_to_work = 1; CHK2 (sock, socket (PF_INET, SOCK_STREAM, 0); CHK (connect (sock, (struct sockaddr *) & addr, sizeof (addr) <0); CHK (pipe (pipe_fd); CHK2 (epfd, epoll_create (EPOLL_SIZE); ev. data. fd = sock; CHK (epoll_ctl (epfd, EPOLL_CTL_ADD, sock, & ev); ev. data. fd = pipe_fd [0]; CHK (epoll_ctl (epfd, EPOLL_CTL_ADD, pipe_fd [0], & ev); // call fork to generate two processes CHK2 (pid, fork (); switch (pid) {case 0: // subprocess close (pipe_fd [0]); // disable the reader printf ("Enter 'exit 'to exit \ n"); while (continue_to_work) {bzero (& message, BUF_SIZE); fgets (message, BUF_SIZE, stdin); // when receiving the exit command, exit if (strncasecmp (message, comment _exit, strlen (comment _exit) = 0) {continue_to_work = 0 ;} else {CHK (write (pipe_fd [1], message, strlen (message)-1) ;}} break; default: // parent process close (pipe_fd [1]); // disable int epoll_events_count, res; while (continue_to_work) {CHK2 (epoll_events_count, epoll_wait (epfd, events, 2, EPOLL_RUN_TIMEOUT); for (int I = 0; I <epoll_events_count; I ++) {bzero (& message, BUF_SIZE); if (events [I]. data. fd = sock) // receiving information from the slave server {CHK2 (res, recv (sock, message, BUF_SIZE, 0); if (res = 0) // The server has been shut down {CHK (close (sock); continue_to_work = 0;} else {printf ("% s \ n", message );}} else // receives information from the sub-process {CHK2 (res, read (events [I]. data. fd, message, BUF_SIZE); if (res = 0) {continue_to_work = 0;} else {CHK (send (sock, message, BUF_SIZE, 0) ;}}}}if (pid) {close (pipe_fd [0]); close (sock) ;}else {close (pipe_fd [1]);} return 0 ;}

 

Related Article

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.