Multiplexing IO (also called I/O multiplexing) monitors I/O events with high concurrency and monitors the time of a large number of descriptors to determine whether I/O conditions are met. Ready: includes read ready events (when data arrives), write ready events (when the buffer has free space), and exception events (when an exception occurs). For the server, a lot of times we monitor read events, and both write events and exception events are used only in certain circumstances.

select

Select model: Events are monitored by descriptors in several event sets and returned when there are ready events in the set. Select actually creates an array space in the kernel to store file descriptors passed in user space for monitoring, and that’s what the kernel does, so we just pass file descriptors, check in user space, and when we have ready events we copy them to user space for processing.

       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>
       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
Copy the code

NFDS: the maximum descriptor of the monitoring descriptor is +1. Fd_set: A set of descriptors (actually a bitmap) whose size depends on FD_SETSIZE=1024. So the maximum file descriptor we can monitor is 1024. Readfd writefds, exceptfds: ready events are read, write the ready event, collection of abnormal ready event.

FD_ZERO(fd_set * fdSET) : Clears the association between fdset and all file handles. FD_SET(int fd, FD_SET *fdset) : Establishes the connection between file handle fd and FDset. FD_CLR(int fd, fd_set * fdSET) : Clears the connection between file handle fd and FDset. FD_ISSET(int fd, fdset *fdset) : checks whether the file handle fd associated with fdset is readable and writable. >0 indicates that the file handle fd is readable and writable.

Unready descriptors in the collection are cleaned up before returning. Timeout: wait timeout event Return value: >0, returns the number of ready events. =0: The monitoring event times out. <0 Monitoring error

Flow 1) Define a descriptor set: Fd_set (bitmap, the maximum is 1024) 2) will monitor collection copy into the kernel, the principle of monitoring is to compile all descriptors polling state 3) when the descriptor ready, before the return, there will be no ready descriptor out 4) user operations, to traverse all descriptors, see which one is still in the collection, 5) copy fd_set to kernel for monitoring Monitoring fd_set, but we can’t let him pass into the kernel, or delivery has changed, and when I come back so we need to define an intermediate variable copy into the kernel, when passed back in the intermediate variable is already prepared the file descriptor, however we can continue to monitor the file descriptor defined variables are monitored.

Select the pros and cons

Advantages: POSIX compliant, cross-platform, monitor timeouts accurate to microseconds Disadvantages: The default value is 1024, depending on the size of FD_SETSIZE. 2) Select implements the monitoring by polling the state in the kernel, so the performance decreases as the number of descriptors increases. 3) Select modifies the value in the monitoring set each time. 4) Select the descriptors in the set to be monitored to copy data to the kernel each time.

poll

Poll is actually similar to SELECT in that it creates a space in the kernel, but rather than monitoring every event, poll monitors a structured collection of events.

struct pollfd{ int fd; short events; // Monitor events short revents; // Ready event}Copy the code

Common events are POLLIN and POLLOUT

 #include <poll.h>
 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
Copy the code

Principle: 2) Poll implements monitoring by copying data into the kernel, and polling traversal monitoring. Performance degrades as the number of file descriptors increases. 3) The user determines which event is ready based on the revents returned and resends it. 4) Poll does not tell the user which descriptor is ready, but only that there are ready events for the user to traverse.

Advantages and disadvantages of poll:

Advantages 1) with the method of event structure to monitor descriptor, simplifies the multiple events set way of monitoring 2) concrete ceiling defect 1) without descriptors not cross-platform 2) increase as descriptor performance degradation poll has been eliminated, because his function can use other model instead, and high performance, For example, epoll. The advantage of SELECT over poll is that poll cannot be cross-platform. But poll is nothing compared to epoll.

Epoll model

Epoll model The highest performing I/O multiplex in Linux has different ready events under epoll. To be ready for a readable event is to accept that the buffer’s data size is greater than the low water mark (typically one byte). Ready for writable events is when the size of the writable buffer’s free space is greater than the low water mark (1B). Epoll in the kernel is a red-black tree for node removal and addition, as well as a two-way rdList for storing a list of ready events. Epoll also uses an event structure for monitoring.

Create an epoll node

       #include <sys/epoll.h>
       int epoll_create(int size);
Copy the code

Function: Create a structure in the kernel, eventPoll {}; In the structure we only care about two parameters, one is red-black tree, the other is two-way linked list rdlist. size: the upper limit of descriptors that can be monitored, but has been ignored since Linux2.6.8, but the parameter must be greater than 0. Return value: Returns a descriptor, the operation handle of epoll.

Add, delete, and modify nodes to epoll trees

       #include <sys/epoll.h>
       int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
Copy the code

Function: Add or remove the eventPoll structure in the kernel to modify the monitored event structure. Epfd: operation handle of the eventPoll structure returned by epoll_create OP: operation to be performed by the user

EPOLL_CTL_ADD: adds event structures to be monitored to eventPoll in the kernel. EPOLL_CTL_DEL: deletes event structures to be monitored from eventPoll in the kernel. EPOLL_CTL_MOD: modifies event structures to be monitored to eventPoll in the kernel

Start monitoring

       #include <sys/epoll.h>
       int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
Copy the code

Start monitoring the time structure nodes saved in the red-black tree in EventPoll and copying ready events to the current two-way linked list RDList. Epfd: eventPoll handle Events: a structure set of ready events maxEvents: used to determine the maximum number of ready events that can be obtained at the last time timeout: the timeout period can be as long as ms.

Steps: 1) The first step tells the kernel to start monitoring the file descriptor. 2) The operating system monitors the descriptor using the event-triggered mode. An event is defined for each descriptor to be monitored, and there is a callback function (ep_poll_callback()) for this event. 4) Epoll_wait does not return immediately, but periodically checks to see if the bidirectional list is empty. To determine whether any descriptor is ready. 5) If the list is not empty, the file descriptor is ready, and epoll_wait returns. Before returning, epoll copies the event structure corresponding to the ready descriptor to the user. 6) Epoll copies the events corresponding to the ready descriptor to the user state, and directly tells the user which descriptor is ready, so that the user can operate the ready descriptor directly.

Advantages and disadvantages of epoll

3) Epoll is an asynchronous blocking operation that calls the operating system to monitor file descriptors. The event callback function is used to monitor the descriptors, avoiding the select cycle polling. Performance does not increase with the file descriptor down 4) initiated epoll call waiting, cycle to judge the kernel epoll ready time list is empty to determine whether there is ready, if you have ready event, will copy the corresponding events to user mode, directly tell the user the descriptor ready, don’t need a cycle of judgment. 5) The event structure of the epoll descriptor needs to be copied to the kernel only once, not every time

Disadvantages 1) not cross-platform 2) Latency is only accurate to milliseconds

Two epoll trigger modes

Horizontal triggering: A readable or writable event is triggered whenever the size of the data in the buffer is greater than the low watermark. Edge triggering: 1) For readable events, the event will be triggered every time a new time button arrives. 2) for writable events, the event will be triggered every time the buffer free space increases from 0 to greater than the low watermark. In general, when both read and write events are monitored, edge triggering is used for writable events (to prevent writable events from firing every time they do not write data but are free). If the readable event is set to edge trigger, the user needs to read the data all at once, but because the amount of data is not known, the data can only be read in a loop from the buffer. Recv blocks when the loop reads but there is no data in the buffer.