Article directory
- 1. Responsibilities of the network `IO`
-
- Operation `IO`
-
- How `IO` operates
- **The specific difference between blocking and non-blocking `IO`:**
-
- Blocking the flow of `IO` in a system call
- The flow of non-blocking `IO` in system calls
- The network programming system call has the function of detection and operation
-
- `accept`:
- `read`:
- `write`:
- 2. The specific processing of system calls when calling non-blocking `IO`
-
- `connect`
- `accept`
- `read`
- `write`
- 3. When the connection is disconnected in the network
-
- active shutdown
- passive close
- 4. Separation detection and operation
-
- Taking `epoll` as an example to introduce `io` multiplexing
-
- establish connection
- Disconnect
- message arrives
- send message
- Detailed explanation of `epoll`
-
- Introduce the four parameter interfaces of `epoll_wait`
- 5. Introducing `Reactor`
-
- What is `reactor`?
- Why there is `reactor`
- Why is `reactor` paired with non-blocking?
- 6. Application of `reactor` in middleware
-
- 1. `redis`
- 2. `memcache`
- 3. `nginx`
1. Network IO
Responsibilities
Operate IO
IO
operation mode
- Blocking
IO
- Non-blocking
IO
Use fcntl
to modify whether fd
is blocking or non-blocking, and then all system calls using this fd
will behave as non-blocking
The specific difference between blocking and non-blocking IO
:
Data is not ready for processing
The process of blocking IO
in system calls
read
blocking IO
call process: first check whether there is data in the kernel buffer, if there is no data, then block and wait, when the client sends us Data, and then our network card driver fills the kernel buffer with data, and then the blocked system call will remove the block, then copy, and then the system call will return
write
blocks the IO
call process: first check whether the kernel buffer can write data (whether it is full), if it is full, then Just block, wait until the network protocol stack sends out the kernel buffer data, he will stop blocking when there is remaining space, write the data into the kernel buffer, and return the number of bytes actually written into the kernel space
**accept
blocks the IO
call process: **Check if there is a node in the full connection queue, if not, it will be blocked and waiting, if there is, it will take out and return to the assigned clientfd
The flow of non-blocking IO
in system calls
Regardless of whether the kernel buffer is writable or readable, it returns directly. Will set errno
if necessary
Network programming system calls have the function of detection and operation
accept
:
- Detection: Whether the full connection has unprocessed connection information
- Operation: Take out the connection from the full connection queue to obtain and generate the customer’s fd and ip port information
read
:
- Detection: Whether the kernel buffer has data or not
- Operation: copy the kernel buffer data to the user mode buffer
write
:
- Detection: Whether the kernel buffer can write data (is it full)
- Operation: Copy the user-mode buffer to the kernel-mode buffer
2. The specific processing of system calls calling non-blocking IO
connect
- Calling
connect
multiple times, the return value may be different from the **seterrno
**, whenerrno
When code> isEISC-ONN
, it tells us that the connection has been successfully established. If it is the first time to callconnect
, it will returnEINPROGRESS
, which tells us that a connection is being established
accept
- If the full connection queue is empty (the client is not connected to the server), then
accept
will return-1
, anderrno
will be set toEWOULDBLOCK
, tells us that the full connection queue is empty
read
read
call to viewerrno
:read = -1 & amp; & amp; errno = EWOULDBLOCK
: means the read buffer has no data yetread = -1 & amp; & amp; errno = EINTR
: It means that it was interrupted when it could be read
write
write
call to viewerrno
:- Same as above, but it means the buffer is full
3. When the connection is disconnected in the network
Active close
shutdown
closes one endclose
is to close the two ends (the first is to recycle resources, and then the read and write ends will be closed accordingly)- Writer of Client is associated with Read of Server, Server The reader is associated with the writer of the client
- So when the client calls
shutdown
to close the reading end, the corresponding writing end of the server will be closed (you need to judge by yourself)
- So when the client calls
Passive close
-
read
returns 0: tells us that the connection is disconnected, more precisely, the server’s read end is closed -
write
returns-1
& amp; & amp;errno = EPIPE
: tells us that the write end of the server is closed -
Why do you need to distinguish between read-end closure and write-end closure?
- Because some server frameworks need to support the half-closed state,
- If the reading end is closed, the server can also call
write
to send the unsent data of this connection, which corresponds to the time before the peer sends thefin
packet in the four recycling part.
- If the reading end is closed, the server can also call
- Because some server frameworks need to support the half-closed state,
4. Separation detection and operation
accept
personally detects whether there are nodes in the full connection queue, but uses io
multiplexing technology to detect whether io
is ready to ensure that when the execution reaches accept
must be io
ready
And io
multiplexing can detect the readiness of multipleio
at the same time
Taking epoll
as an example to introduce io
multiplexing
Establish a connection
-
io
detects the processing flow of receiving connectionsocket
bind & amp;listen
- Listen for read events (
epollin
)- How does
epoll
monitor!epoll
will listen to the read event oflistenfd
. When we connect and listen successfully, There will be one more node on the full connection queue, and this node will send a signal< /strong>(EPOLLIN
) to tellepoll
(alsoselect, poll
), it will trigger the read event, which means that the connection is receivedio
is ready, soaccept
will be called later, and nowaccept
will only operate without detection, becauseio
Multiplexing has been checked
- How does
-
Process flow of
io
detecting active connection-
The server acts as a client to connect to some services such as
mysql
-
Listen for write events (
epollout
)-
The server calls
conncet
to send aSYN
packet. At this time, the status isEINPROGRESS
, how to detect it by multiplexingio
Whether the connection is successfully established,io
multiplexing will detect whether the last handshake of the three-way handshake is sent, will be sent when the last handshake of the three-way handshake is sent A signal, tellingepoll
that the write event is triggered (so whenepoll
listens to the write event trigger, it means that our connection is established successfully) -
The following is a small
demo
whereepoll
is responsible for the detection ofconnect
// Set sockfd non-blocking connect(sockfd, (struct sockaddr *) & server_addr, sizeof(server_addr)); epollfd = epoll_create(EPOLL_SIZE); // 10 event.events = EPOLLOUT; event.data.fd = sockfd; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event); epoll_wait(epollfd, events, EPOLL_SIZE, -1); // -1 means blocking if (events[0].events & amp; EPOLLERR || events[0].events & amp; EPOLLHUP) { printf("connect failed\\ "); exit(EXIT_FAILURE); } else if (events[0].events & EPOLLOUT) { printf("connect success\\ "); // send a message ret = write(sockfd, send_buf, strlen(send_buf)); if (ret == -1) { perror("write"); exit(EXIT_FAILURE); } }
-
-
Connection disconnected
Detect customer disconnection by judging event[i].events
EPOLLRDHUP
: indicates that the server read end is closedEPOLLHUP
: indicates that both the read and write ends of the server are closed
Message arrived
- Client
fd
triggersEPOLLIN
(detection) and then callsread
(operation)
Message sending
- Client
fd
triggersEPOLLOUT
(detection), then callswrite/send
(operation)
epoll
Detailed explanation
epoll_create
will create a red-black tree and a double-ended queue
epoll_ctl
is to add, delete, and modify the red-black tree. At the same time, it will establish a callback relationship with the network card driver. When the response event is triggered, the callback function will be called. This callback function will copy the triggered event to rdlist
in the doubly linked list;
Calling epoll_wait
will copy the ready events in rdlist
to user mode (after copying out, the events in the kernel mode ready queue will be cleared)
Introduce the four parameter interfaces of epoll_wait
-
parameter
-
epoll
file descriptor -
An array of user space, used to receive things in the ready queue in kernel space
-
How many events are expected to be copied
-
Timing (in milliseconds)
-
epoll
is a synchronousio
, there is no blocking or non-blocking, but the blocking of the function can be controlled bytimeout
,If it is set to
-1
, it will be blocked (the ready queue will always block if there is no event),Set to
0
will behave as non-blocking (ready queue)
-
-
-
return
- Return how many events are actually fetched
5. Introduce Reactor
It is to convert the operation of io
into the processing of events
What is reactor
?
A server has many io
, we will submit them to the epoll
kernel management, once there is an event (readable or writable) on io
, it will The callback function corresponding to the trigger event (readable or writable) handles the business. Each fd
has a corresponding structure, which stores some necessary information (callback function, independent read and write buffer)
Why is there a reactor
What does reactor
add on the basis of epoll
, and what are the benefits?
epoll
: he is the management ofio
reactor
: is the management of events, different events correspond to different callback functions- Due to
sock_item
encapsulation, unprocessed events are placed in an independentbuffer
(independent of otherfd
(clients))- benefit?
- For example, if a
httpserver
is implemented, ourrecv
can only receive1024
, but theget
request has2000
characters, each received is placed infd
‘s ownbuffer
, and will not be affected by otherfd
inputs Influence
- For example, if a
- benefit?
Why is
reactor
paired with non-blocking?
Why does io
multiplexing help us detect that io
is ready, why use non-blocking io
, consider three situations
-
multi-threaded environment
-
Multiple threads use the same
epoll
to monitor the samefd
When there is
io
on thisfd
, the node of the ready queue will notify theepoll
of each thread that there is a new connection established here.If you use blocking
io
, when a thread’sepoll_wait
takes it out, other threads’epoll_wait
will be blocked there**Shocking crowd! :** There is a Neptune who has many girlfriends, each of whom is called his wife. Once he met these girlfriends at the same time, he made a doctor’s wife. They all agreed
-
-
edge triggered case
-
Call
epollwait
to take out the corresponding node inrdlist
when theio
event occurs on the client sidefd
code>readbuf will not automatically put thefd
into therdlist
(butlt
will be in thereadbuf
automatically puts data intordlist
when there is still data, and then letsepollwait
trigger)Under edge triggering,
readbuf
must read the data empty at one time, otherwise there will be sticky packets similar totcp
, iffd
is set to block, Thenreadbuf
will not return but continue to block when it has been read empty, so it must be set to non-blocking to judge thatread
has been read
-
-
select bug
- When a new data segment arrives in a socket receiving buffer, then select reports that the socket descriptor is readable, but then, the protocol stack discards this segment after checking that the new segment has a checksum error. At this time, calling read has no data to read. If the socket is not set to be non-blocking, then read will block the current thread.
6. Application of reactor
in middleware
1, redis
Using a single reactor
-
specific environment
-
kv
, data structure, memory databaseUse
key
to checkvalue
,value
can support a variety of data structures, and these data operations are all performed on memory -
Command processing is single-threaded
-
-
redis
why use a singlereactor
- Only a single reactor can be used, because the core business logic is single-threaded.
- It is very simple to operate the data structure, and the time complexity of the operation command is relatively low
-
How does
redis
deal withreactor
general flow
- Create l
istenfd
bind listen
listenfd
register read time- Read event trigger callback
accept
clientfd
registers for read events- read event trigger
- Create l
-
What optimizations have
redis
made forreactor
- Turn on multi-threading, bind the read data and solution protocol together in another thread, put the package and write data in another thread for processing, and put the middle business logic in the main thread operation
2, memcache
Multiple reactor
- What optimizations have been made for reactor
In the main thread, there is a reactor
specially used to receive connections. There are as many child reactor
as there are connections. One connection creates a thread, and the interaction between threads It uses pipe
to communicate
3, nginx
Multiple reactor
Multi-process, each process has its own epfd
, listening to the same listenfd
, the user layer handles the shock group to customize load balancing
The knowledge points of this column are based on the systematic learning of