SNET
Simple Linux net lib in C++20.
Five I/O models
- An input operation usually includes two stages
- Waiting for data to be ready, copying it to a kernel buffer when it arrives from the network
- Copying data from the kernel buffer to the process buffer
Synchronous I/O
- The four models of synchronous I/O operations must complete one task before doing the next, which will block the thread. They are all the same in the second stage, and the main difference is in the first stage
- Blocking I/O: The most common model. All sockets in Linux are blocked by default. The process calls recvfrom, the kernel waits for data to arrive, and the user thread is blocked. After the kernel receives the data, it copies it to the process buffer and returns the result. At this time, the user is unblocked. During the entire I/O request process, the user thread is blocked and cannot do anything, and the CPU resource utilization is low
- Non-blocking I/O: That is, polling the kernel. When the process calls recvfrom, no data is returned. The kernel does not block the user, but returns an EWOULDBLOCK error. Although no data is read, the user can get the return result immediately. When the user receives an error code, knowing that the kernel is not ready, the user will continue to send requests until the kernel is ready for data. At this time, the kernel will copy the data to the process buffer and then return. Polling consumes a lot of CPU resources. Generally, non-blocking I/O is rarely used directly, but this feature is used in other I/O models
- I/O multiplexing: The most commonly used I/O model, which can be understood as a capability that some processes need to inform the kernel in advance, so that once the kernel finds that one or more I/O conditions specified by the process are ready (that is, the input is ready to be read, or the descriptor can take on more output), it will notify the process. I/O multiplexing is based on the select function provided by the kernel and is used to avoid the polling waiting problem of non-blocking I/O. The user first puts the file descriptor to be operated on I/O into select, and select will block until the file descriptor is readable and returns. The advantage of select is that it can directly monitor multiple file descriptors with a single thread. If blocking I/O is used, multiple threads are required to achieve this goal. select will block the thread (but not the socket), so the I/O multiplexing model is also called the asynchronous blocking I/O model, but it is not really asynchronous I/O
- signal-driven I/O: install the signal processing function through the sigaction function. If the data is not available, the process continues to work without blocking. When the data is ready, the kernel generates a SIGIO signal for the process. Then you can call recvfrom in the signal processing function to read the data and notify the main loop that the data is ready for processing. You can also immediately notify the main loop to read the datagram. The advantage of this model is that it is not blocked while waiting for data to arrive
Asynchronous I/O
- asynchronous I/O: notify the kernel to start an operation, and the kernel notifies the user after the operation is completed. In the signal-driven model, the kernel notifies the user when the I/O operation is started, and in the asynchronous I/O model, the kernel notifies the user when the I/O operation is completed. Asynchronous I/O is not commonly used compared to I/O multiplexing. I/O multiplexing plus multi-threaded task processing architecture can meet the requirements of most high-performance concurrent programs