2016-03-13 3 views
0

Я создаю прослушивающий сокет с отставанием 1 и подключаю 64 гнезда к нему.Очень странное время подключения в Linux

укорочено

#define _POSIX_C_SOURCE 199309L 

#include <arpa/inet.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/time.h> 
#include <time.h> 

int main() { 
    int server_socket = socket(AF_INET, SOCK_STREAM, 0); 
    struct sockaddr_in server_address = {0}; 
    server_address.sin_family = AF_INET; 
    server_address.sin_addr.s_addr = htonl(INADDR_ANY); 
    server_address.sin_port = htons(8000); 
    bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)); 
    if (listen(server_socket, 1) == 0) { 
     printf("Listening\n"); 
    } else { 
     printf("Failed to listen\n"); 
     return 1; 
    } 

    for (int i = 0; i < 64; i++) { 
     int client_socket = socket(AF_INET, SOCK_STREAM, 0); 
     struct timespec start; 
     clock_gettime(CLOCK_MONOTONIC, &start); 
     if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == 0) { 
      struct timespec end; 
      clock_gettime(CLOCK_MONOTONIC, &end); 
      double elapsed = end.tv_sec - start.tv_sec + (end.tv_nsec - start.tv_nsec)/1e9; 
      printf("Connected socket #%d in %.3lfs\n", i, elapsed); 
     } else { 
      printf("Failed to connect socket #%d\n", i); 
     } 
    } 
} 

Выход:

$ gcc -o socket -std=c99 socket.c 
$ ./socket 
Listening 
Connected socket #0 in 0.000s 
Connected socket #1 in 0.000s 
Connected socket #2 in 0.000s 
Connected socket #3 in 0.000s 
Connected socket #4 in 1.000s 
Connected socket #5 in 0.000s 
Connected socket #6 in 3.004s 
Connected socket #7 in 0.000s 
Connected socket #8 in 3.004s 
Connected socket #9 in 0.000s 
Connected socket #10 in 3.004s 
Connected socket #11 in 0.000s 
Connected socket #12 in 3.004s 
Connected socket #13 in 0.000s 
Connected socket #14 in 3.004s 
Connected socket #15 in 0.000s 
Connected socket #16 in 3.004s 
Connected socket #17 in 0.000s 
... 

Первые четыре соединения являются мгновенными, пятый занимает 1 секунду, а затем соединения не колеблется в диапазоне от 0 до 3 секунд, пока все сокеты соединяются и программа выходит. Такое поведение на 100% повторяемо.

Я читал подробно о TCP-соединениях, сетевой документации по Linux и other resources.

Но я все еще не могу объяснить, что происходит.

Почему такое время соединения меняется так дико?


Информация о системе

$ uname -a 
Linux paul 3.19.0-51-generiC#58~14.04.1-Ubuntu SMP Fri Feb 26 22:02:58 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux 

(/etc/sysctl.conf пуст.)

+0

Что-нибудь изменится, если вы 'подключения()' к реальным IP как '127.0.0.1' вместо' INADDT_ANY'? Если вы на самом деле 'accept()' входящие соединения? –

ответ

1

Документах для listen объяснить это, «если основной протокол поддерживает повторную передачу, запрос может быть проигнорирован так что последующая перезагрузка при соединении будет успешной ». Если вы закроете отставание, вы увидите, что момент начала задержек начинается.

+0

Хорошо. Но где первые 4 быстро? И почему это только любая другая связь? Какие тайм-ауты или настройки вызывают длительное время соединения? Я ищу понимать Linux TCP за пределами «сделать это число достаточно высоким, а что-то еще произойдет». –

+1

@PaulDraper Это состояние гонки. Есть одна часть кода, которая добавляет в очередь на прослушивание и один раз кусок кода, который истощает очередь прослушивания. Если соединение происходит, когда есть место в очереди на прослушивание, оно завершается немедленно. Если нет, это задерживается до повторной передачи. –

+0

Изменение происходит потому, что вы дождались завершения одного соединения, прежде чем пытаться выполнить следующее. Таким образом, соединение, которое должно подождать, почти всегда оставляет очередь прослушивания пустой для следующей попытки. –

1

Как отметил Дэвид Шварц, это связано с вашим отставанием. TCP-код, обрабатывающий запрос SYN, считает, что очередь ожидания заполнена, а также очередь SYN. Как видно here

1287   /* Accept backlog is full. If we have already queued enough 
1288   * of warm entries in syn queue, drop request. It is better than 
1289   * clogging syn queue with openreqs with exponentially increasing 
1290   * timeout. 
1291   */ 
1292   if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { 
1293     NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); 
1294     goto drop; 
1295   } 

После сформулированное условие достигается, ваши SYN пакеты падения. ретрансляция клиента произойдет через 3 секунды (начальный SYN), которые получают-х приняло

Вы не увидите какие-либо задержек с подключением, если вы установите накопившиеся 65

Смежные вопросы