Нормально закрывать TCP-коннект между А и Б по инициативе А так:
- А шлёт FIN («я всё сказал»)
- Б шлёт FIN + ACK («вас понял, я тоже всё»)
- А шлёт ACK («вас понял»).
Три вопроса вопроса:
-
Непонятно, зачем посылать FIN на шаге (1), когда можно послать RST и забыть обо всём. Видимо это не экологично: потеря RST приведёт к сохранению коннекта на Б, в сценарии выше (1) можно повторить, если долго не будет (2)?
-
А есть какая-то другая причина, почему после (1) коннекшн ещё остаётся? Может ли Б после получения FIN что-то PUSH в этот коннекшн? Но это бессмысленно, софтина на А уже вызвала close() на сокете.
-
Проводил эксперимент:
- A - C++ сервер вида «socket();setsetsockopt();bind();listen(port 12345);accept();». Также, в этом сервере написано «По приходу чего-нибудь в коннект, вычитать всё через read() и сразу сделать close(socket)»;
- Б: «nc 127.0.0.1 12345»
- Б что-то PUSH в коннекшн (печатаю в nc рандомную строку, жму enter), A это вычитывает из сокета и делает сразу close(socket);
- В tcpdump видно, как от А к Б прилетает FIN + ACK. Зачем тут ACK? ACK на PUSH прилетело пакетом ранее….
- В ответ на FIN от Б прилетает один ACK, как будто nc не собирается закрывать. Всмысле? Какой смысл тут не хотеть закрывать?
- Ввожу в nc ещё одну строку, отправляю (от Б летит PUSH + ACK). Зачем тут опять ack?
- От A приходит RST. Это уже выглядит как «слыш ты кто»?