Epoll learning. Difference Between epoll and select and pool

Source: Internet
Author: User
Tags epoll

 

In Linux network programming, select is used for event triggering for a long time. In the new Linux kernel, epoll is a mechanism to replace it.

Compared with select, epoll does not reduce the efficiency as the number of FD listeners increases. in the select implementation in the kernel, it uses Round Robin to process data. The more data in the round-robin FD, the more time it will naturally take.

Three epoll Functions

1) int epoll_create (INT size );

Create an epoll handle and the size is used to tell the kernel the total data size of the listener.

It should be noted that after the epoll handle is created, it will occupy an FD value. After epoll is used, close must be called to close it; otherwise, FD may be exhausted.

2) int epoll_ctl (INT epfd, int op, int FD, struct epoll_event * event );

Epoll registers the function. The first parameter is the returned value of epoll_create.

The second parameter represents an action, represented by three macros.

Epoll_ctl_add: register a new FD to epfd.

Epoll_ctl_mod: modifies the listener events of the registered FD.

Epoll_ctl_del: delete an FD from epfd

The third parameter is the FD to be monitored.

The fourth parameter tells the kernel what to listen.

The struct_event structure is as follows:

typedef union epoll_data {    void *ptr;    int fd;    __uint32_t u32;    __uint64_t u64;} epoll_data_t;struct epoll_event {    __uint32_t events; /* Epoll events */    epoll_data_t data; /* User data variable */};

 

Events can be a collection of the following macros:

Epollin: indicates that the corresponding file descriptor is readable (including that the Peer socket is normally disabled)

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

Epollpri: indicates that the corresponding file descriptor has urgent readable data.

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. This is relative to level triggered.

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

 

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

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, and it is also said to be permanent blocking. this function returns the number of events to be processed. If 0 is returned, the Operation has timed out.

 

About et. Lt working modes

The et mode is notified only when the status change is sent. The state change does not include any unprocessed data in the buffer, that is. to use the et mode, read/write until an error occurs. many people reflect why only a part of data is received in the et mode and no notification is received, mostly because of this.

The lt Mode means that the notification will continue as long as there is no data to be processed.

 

Epoll Model

Create an epoll handle using create_epoll (INT maxfds). maxfds supports the maximum number of epoll handles. This function returns a new epoll handle, and all subsequent operations will be performed using this handle. After you use up, remember to use close () to close the created epoll handle.

Then, in your main network loop, each frame calls epoll_wait (INT epfd, epoll_event events, int Max events, int timeout) to query all network interfaces, check which one can be read and which one can be written. The basic syntax is:
NFDs = epoll_wait (kdpfd, events, maxevents,-1 );
Here, kdpfd is the handle created with epoll_create. events is a pointer to epoll_event *. After the epoll_wait function operation is successful, epoll_events stores all read and write events. Max_events is the number of all socket handles to be monitored. The last timeout is the epoll_wait timeout. If it is 0, it indicates immediate return. If it is-1, it indicates waiting until there is an event range, if it is an arbitrary positive integer, it indicates waiting for such a long time. If there is no event, the range is. Generally, if the main loop of the network is a separate thread, you can use-1 to ensure some efficiency. If it is in the same thread as the main logic, 0 can be used to ensure the efficiency of the main loop.

The epoll_wait range should be followed by a loop to repeat all events.

 

 

 

# Include <iostream> # include <sys/socket. h> # include <sys/epoll. h> # include <netinet/in. h> # include <ARPA/inet. h> # include <fcntl. h> # include <unistd. h> # include <stdio. h> # include <errno. h> using namespace STD; int main (INT argc, char * argv []) {int Maxi, listenfd, connfd, sockfd, epfd, NFDs; ssize_t N; char line [100]; listenfd = socket (af_inet, sock_stream, 0); // declare the epoll_event struct variable, EV is used to register events, and array is used to return the event struct epoll_event eV to be processed, events [20]; epfd = epoll_create (1, 256); eV. date. FD = listenfd; eV. events = epollin | epollet; epoll_ctl (epfd, epoll_ctl_add, listenfd, & eV); // register epoll event struct sockaddr_in serveraddr; bzero (& serveraddr, sizeof (serveraddr )); char * local_addr = "127.0.0.1"; inet_aton (local_addr, & (serveraddr. sin_addr); serveraddr. sin_port = htons (8888); BIND (listenfd, (sockaddr *) & serveraddr, sizeof (serveraddr); Listen (listenfd, listenq); Maxi = 0; (;;) {// wait for the epoll event to occur NFDs = epoll_wait (epfd, events, 20,500); // process all events that occur for (INT I = 0; I <NFDs; I ++) {If (events [I]. data. FD = listenfd) // if a new socket user is detected to connect to the bound socket port, establish a new connection {struct sockaddr_in clientaddr; socketlen_t clilen; connfd = accept (listenfd, (sockaddr *) & clientaddr, & clilen); char * STR = inet_ntoa (clientaddr. sin_addr); cout <"accept a connection from" <STR <endll; eV. data. FD = connfd; eV. events = epollin | epollet; epoll_ctl (epfd, epoll_ctl_add, connfd, & eV);} else if (events [I]. events & epollin) // if it is a connected user and receives data, read {sockfd = events [I]. data. FD; n = read (sockfd, line, 100); line [N] = '\ 0'; cout <"read MSG:" <line <Endl; eV. data. FD = sockfd; eV. events = epollout | epollen; epoll_ctl (epfd, epoll_ctl_mod, sockfd, & eV);} else if (events [I]. events & epollout) {sockfd = events [I]. data. FD; write (sockfd, line, n); eV. data. FD = sockfd; eV. events = epollin | epollet; epoll_ctl (epfd, epoll_ctl_mod, sockfd, & eV) ;}} return 0 ;}

 

 

Difference between epoll and select and poll

1. support a process to open a large number of socket Descriptors (FD)

The most intolerable thing about select is that the FD opened by a process has certain limitations.Fd_setsizeSet, the default value is 2048. For im servers that need to support tens of thousands of connections, there are obviously too few. At this time, you can choose to modify this macro and then re-compile the kernel, but the materials also pointed out that this will bring about a reduction in network efficiency.

2. Io efficiency does not decrease linearly as the number of FD increases

Another weakness of the traditional select/poll is that when you have a large set of sockets, but due to network latency, only some of the sockets are "active" at any time, however, each select/poll call will linearly scan all sets, resulting in a linear decline in efficiency. However, epoll does not have this problem. It only performs operations on "active" sockets-this is because epoll is implemented based on the callback function on each FD in kernel implementation.

Epoll uses event-based readiness notification. In select/poll, the kernel scans all monitored file descriptors only after a certain method is called, and epoll registers a file descriptor through epoll_ctl () in advance, once a file descriptor is ready, the kernel uses a callback mechanism similar to callback to quickly activate the file descriptor. When the process calls epoll_wait (), it is notified.

3. Use MMAP to accelerate message transmission between the kernel and user space

Both select, poll, and epoll require the kernel to notify users of FD messages. It is important to avoid unnecessary memory copies, epoll is implemented through the same memory of the user space MMAP kernel.

4. kernel fine-tuning

This is not the advantage of epoll, but the advantage of the entire Linux platform.

 

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.