Я написал простую клиентскую программу для выдачи 10000 соединений с использованием 100 потоков за очень небольшую продолжительность. И простая серверная программа с listen backlog
установите значение 20 с помощью epoll, чтобы принять любое новое соединение и записать общее количество соединений. я использовал ulimit -n
чтобы убедиться, что он больше, чем 20000, поэтому должно быть достаточно ресурса fd.
Но после серверной программы accept
Как 8800, 9400 (не фиксированные) соединения, он просто перестал принимать любое новое соединение. Клиент использовал блокировку connect
установить соединения, и все эти 10000 вызовов connect
вернул успех. Затем все зависает, больше нет пакетов (нет повторной передачи), больше нет принятого соединения.
Но как только я закрыл клиентскую программу, серверная программа начала принимать оставшиеся соединения после закрытия некоторых соединений (и в итоге приняла все 10000 соединений и закрыла все эти соединения).
Когда я изменился backlog
до 100 или более, все 10000 соединений были приняты без каких-либо проблем. (так что это не проблема ресурса fd)
Я знаю, что при заполнении очереди, Linux может просто игнорировать входящие ACK
трехстороннего рукопожатия, оставив соединение с клиентом установленным, но соединение с сервером все еще не установленным, а затем дайте механизму ретрансляции работать. И в итоге сервер ретранслирует SYN/ACK
Пакет, клиент отвечает ACK
восстановить это соединение, если доступна очередь приема сервера. Если в очереди нет свободного места, сервер игнорирует ACK
снова.
Но когда я использую Wireshark для мониторинга этих повторных передач, я обнаружил, что только небольшое количество SYN/ACK
произошла повторная передача (например, 100 ~ 200, что намного меньше, чем количество потерянных соединений, которое составляет от 500 до 1500), и они передаются повторно один или два раза, все меньше значения, указанного в /proc/sys/net/ipv4/tcp_synack_retries
, Я осмотрел некоторые из этих ретранслируемых SYN/ACK
пакеты, все из которых получены ACK
с клиента. Но количество ретранслируемых SYN
пакеты от клиента были большими.
Итак, каковы основные детали?
Когда резерв будет заполнен и файлы cookie SYN включены, ядро активирует временный режим потока SYN. Эта диаграмма показывает, как работают файлы cookie (источник):
Когда SYN-флуд был активирован, все ACK, отправленные с клиента, будут сброшены. Сервер отправил только SYN / ACK и cookie клиенту, таблица кэша cookie будет намного меньше таблицы сокетов, чтобы поддерживать активное соединение.
В этом случае на стороне клиента сокет считался установленным, но на стороне сервера ничего не открывалось (полуоткрытое соединение).
Когда клиентское приложение закрывает сокет, пакет FIN с установленным флагом ACK будет отправлен на сервер с файлом cookie внутри, сервер увидит, что соединение имеет ACK, в этот момент, если резерв не заполнен, сервер будет попробуйте восстановить соединение из куки. Если файл cookie действителен (в пределах допустимого туда-обратно), сокет будет добавлен в очередь невыполненных работ и может быть обработан как обычный сокет.
Это означает, что, когда был активирован режим куки-файла SYN и очередь невыполненных заданий не заполнена, если клиент отправляет некоторые данные на сервер через полуоткрытые сокеты, функция accept () вернет новое соединение с поступлениями.
Других решений пока нет …