Congestión de TCP

Primero mire un
código de servidor de demostración :

package io.unittest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

/**
 * Author: ljf
 * CreatedAt: 2021/3/28 上午10:05
 */
public class SocketIOProperties {
    
    

    private static final int RECEIVE_BUFFER = 10;
    private static final int SO_TIMEOUT = 0;
    private static final boolean REUSE_ADDR = false;
    private static final int BACK_LOG = 2; // 连接的等待队列满了之后还能拍几个,linux一切皆文件嘛,意味着等着不分配文件描述符的有两个
    private static final boolean CLI_KEEPALIVE = false;
    private static final boolean CLI_OOB = false;
    private static final int CLi_REC_BUF = 20;
    private static final boolean CLI_REUSE_ADDR = false;
    private static final int CLI_SEND_BUF = 20;
    private static final boolean CLI_LINGER = true; // 服务关闭后端口是否立即释放
    private static final int CLI_LINGER_N = 0;
    private static final int CLI_TIMEOUT = 0;
    private static final boolean CLI_NO_DELAY = false;

    public static void main(String[] args) {
    
    
        ServerSocket server = null;
        try {
    
    
            server = new ServerSocket();
            server.bind(new InetSocketAddress(9090), BACK_LOG);
            server.setReceiveBufferSize(RECEIVE_BUFFER);
            server.setReuseAddress(REUSE_ADDR);
            server.setSoTimeout(SO_TIMEOUT);
        } catch (SocketException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("server up use 9090 !");

        try {
    
    
            while (true) {
    
    
                System.in.read(); // 这里阻塞住,看没有客户端的情况下,server端怎么处理连接

                Socket client = server.accept();

                System.out.println("client port: " + client.getPort());

                client.setKeepAlive(CLI_KEEPALIVE);
                client.setOOBInline(CLI_OOB);
                client.setReceiveBufferSize(CLi_REC_BUF);
                client.setReuseAddress(CLI_REUSE_ADDR);
                client.setSendBufferSize(CLI_SEND_BUF);
                client.setSoLinger(CLI_LINGER, CLI_LINGER_N);
                client.setSoTimeout(CLI_TIMEOUT);
                client.setTcpNoDelay(CLI_NO_DELAY);

                // client.read //阻塞 没有 -1 0
                new Thread(
                        () -> {
    
    
                            try {
    
    
                                InputStream in = client.getInputStream();
                                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                                char[] data = new char[1024];
                                while (true) {
    
    
                                    int num = reader.read();

                                    if (num > 0) {
    
    
                                        System.out.println("client read some data is : " + num + " val :" + new String(data, 0, num));
                                    } else if (num == 0) {
    
    
                                        System.out.println("client readed nothing!");
                                        continue;
                                    } else {
    
    
                                        System.out.println("client readed -1 ..."); // 客户端断开,就是-1
                                        System.in.read();
                                        break;
                                    }
                                }
                            } catch (IOException e) {
    
    
                                e.printStackTrace();
                            }
                        }
                ).start();
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                server.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

Hay System.in.read (), bloqueando.
Inicie el programa del servidor, bloquee el principal y ninguna aplicación reciba. En este momento, el tamaño del búfer es 0. En
Inserte la descripción de la imagen aquí
este momento, se inicia un cliente para simular el envío de datos del cliente. . En este momento, el búfer comienza a aumentar. Si no es
Inserte la descripción de la imagen aquí
suficiente, continúe enviando al búfer para que estalle. Por ejemplo, si lo envío a 1152, no aumentará.
Inserte la descripción de la imagen aquí
Como no aumenta, los datos excesivos será descartado. ¿Se pierde la cabeza o la cola? En este momento, el servidor Presione Enter, salte el bloque, reciba los datos y descubra que la cola está perdida. Eso es tcp congestión.

Cómo resuelve tcp la congestión

El mecanismo de la ventana sigue siendo el modelo del servidor que se bloquea arriba, vea la imagen

Inserte la descripción de la imagen aquí
Cuando el cliente se conecta, me dice cuántas ventanas ganan y el tamaño del paquete de datos es mss (1460, que es el 1500 de mtu en ifconfig menos 20 bytes cada uno ocupado por ip y puerto), y luego el servidor le dice al cliente su propio win y mss, luego el cliente confirma, y ​​luego se establece la conexión y luego se comunica.
En el proceso de cada interacción de datos de comunicación, el cliente y el servidor se dicen a sí mismos cuántas ventanas hay. Si la ventana del servidor no es suficiente, se bloqueará hasta que se procesen los datos (la aplicación pasará al siguiente paso). ), cuando hay una ventana libre, se envía un paquete de confirmación al cliente para notificar que se abandona la cola y el cliente continúa enviando paquetes al servidor. Lo mismo ocurre con el cliente. Esto asegura que el paquete tcp no se pueda perder. Eso es control de la congestión .

Supongo que te gusta

Origin blog.csdn.net/weixin_39370859/article/details/115284992
Recomendado
Clasificación