An example shows the relationship between the sending buffer, the receiving buffer, and the sliding window protocol.
In the previous articles, I briefly introduced the relationship between the above concepts in TCP network programming and the behavior of several basic socket system calls. Here I will give an example, for each tcp socket, there is a sending buffer and the receiving buffer corresponding to it. Therefore, only single-direction communication, no interaction, and no send at the recv end, do not recv on the send end. Let's look at the meaning.
I. recv end
Prepare the accept on the listening socket. do not perform any operation after the accept ends. sleep is used for a long time, that is, do not accept data on the recv end, And recv data after the sleep ends.
Ii. send end
Check the maximum size of the sending buffer supported by the system kernel by default, cat/proc/sys/net/ipv4/tcp_wmem. The last parameter is the maximum size of the sending buffer. The configuration file that accepts the largest buffer is in tcp_rmen.
Sets the socket to block. The buffer sent at a time is greater than the data size that the maximum sending buffer can hold. The sending ends at a time and the data length that is promised to be sent after the sending is returned.
Test results:
Phase 1:
Receiver Performance: when data is sent at the beginning, the receiver is in a slow start state, and the size of the sliding window increases. However, because the receiver does not process data in the receiver buffer, the sliding window is getting smaller and smaller (because the win size in the receiver's response sender indicates the amount of data that the receiver can accept, and the size of the data sent by the sender next time cannot exceed the win size in the response ), the size of win displayed in the last response from the sender to the ACK is 0, indicating that the receiver cannot accept data.
Sending end performance: the sending end cannot return all the time. If the receiving end keeps responding to win 0, the sending end will never return, this deadlock continues until the end of sleep at the receiving end.
Cause Analysis: First, you need to understand several facts. Blocking I/O will wait until this operation is completed. The sender can only clear the data in the sending buffer after receiving the response from the receiver.
If there is no recv at the receiving end, there will always be data in the receiving buffer of the receiving end. If the receiving buffer is full, the sliding window is 0, and the sending end cannot send data. But why can't the send operation be rejected? The send operation only copies the data in the application buffer to the sending buffer. However, the data in the sending buffer does not completely obtain the ACK response from the receiving end. Therefore, the data in the sending buffer cannot be discarded temporarily, as a result, the sending buffer is filled up, so that the data in the application layer cannot be copied to the kernel sending buffer, and it will be blocked until the application layer data can be copied to the sending buffer, when will this operation be triggered? This operation is performed only when the sender responds to win value greater than 0.
Phase 2;
Receiver: Call the recv system after sleep ends. At this time, the sliding window of the receiver starts to be greater than zero. In this way, the sender is awakened to continue sending data.
Sending end: the sending end receives a response from the receiving end whose win value is greater than 0. At this time, the sending end can copy the data in the buffer of the application layer to the sending buffer of the kernel.
Cause analysis: the Receiver calls recv to copy the data in the kernel accept buffer to the application layer, so that the sliding window is greater than 0, which inspires the sender to continue sending data, as the sender can send data, the kernel protocol stack sends the data in the sending buffer to the receiver, so that the sending buffer has space, then, the send operation can copy the data at the application layer to the sending buffer! This operation always persists until the send operation returns. This means that all the data on the application layer is copied to the sending buffer, but it does not mean that the data is sent to the peer end. A success message sent to the peer is that the sender receives the ACK response from the peer. Only then can the sender discard the data in the sending buffer. The reason for not discarding is that you are always ready to resend lost/wrong data!
Ps: TCP communication in order to ensure reliability, each data sent must obtain the ACK of the other party to confirm that the other party has received the data (only ensure that the other party has received the data in the TCP receiving buffer, but it is not guaranteed that the application of the other party obtains the data. At this time, if the application stops waiting for the other party's ACK message every time it is sent, it is obviously a great waste of resources and low efficiency, then a sliding window appears.
The sender's sliding window maintains the number of frames currently sent, the timer of the sent frames, and the current window size of the receiver (ACK notification by the receiver, generally equal to the size of the received buffer-unprocessed message packets). The receiver's sliding window stores received frame information and the expected frame number of the next frame, the specific working principle of the sliding window is not mentioned here.
A socket has two sliding windows (one sendbuf and one recvbuf). The size of the two windows is set through the setsockopt function. The problem lies here, the configured window size does not take effect. The final troubleshooting result shows that the setsockopt function was added later and is written after the listen function, in this way, the socket generated by each accept does not inherit the window size set by the main socket ......
Solution: The setsockopt function is prior to the listen function, so that the recvbuf has been available before the server program starts listening. The link after accept gets the recvbuf, and the program runs, the packet capture window is already in the specified size.
1. The hop window size of TCP is actually the number of bytes of the socket's receiving buffer.
2. The buffer size must be set before listen for the socket on the server, because the new socket generated in accept will inherit the buffer size of the listening socket. For the client socket, you must set the buffer size before connet. Because connet requires three handshakes, the recipient's window size will be notified. It makes no sense to set the buffer after connet.
3. Because the buffer size is represented by only 16 bits in the TCP header, the maximum value is 65536. However, in some cases, a larger sliding window is required. In this case, an extended sliding window is used, for example, optical fiber high-speed communication network or satellite persistent connection network, the window size should be as large as possible. The expanded 32-bit sliding window is used.