Когда TCP-соединение закрывается на одном конце соединения - другой конец получает FIN
и отвечает ACK
. Затем этот конец соединения переходит в CLOSE_WAIT
состояние. После close()
вызова на этом конце TCP отправляет FIN
пакет и переходит в LAST_ACK
состояние. Однако он никогда не переходит в TIME_WAIT
состояние.
Теперь предположим, что Хост A вызывает close()
сокет и отправляет FIN
пакет Хосту B. Хост A входит в FIN_WAIT_1
состояние. Хост B получает FIN
пакет, отправляет ACK
и затем входит в CLOSE_WAIT
состояние. Однако ACK теряется где-то в маршрутизаторе восходящего потока.
Тем временем, Хост B звонит close()
(напомним, что Хост B находится в CLOSE_WAIT
состоянии) и отправляет FIN
пакет Хосту A. Хост B теперь входит в LAST_ACK
состояние. Хост A получает FIN
пакет и отвечает ACK
. Затем он входит в CLOSING
состояние.
На другом конце Хост B все еще находится в LAST_ACK
состоянии. Затем он получает ACK
от Хоста A и входит в CLOSED
состояние. Вспомним, что ACK
от Хоста B к Хосту A был сброшен, и Хост A не переслал свой FIN
пакет. Хост A пересылает свой FIN
пакет по тайм-ауту, однако Хост B закрыл соединение.
Хост А теперь застрял в CLOSING
состоянии? Может ли разрыв соединения продолжаться? Что происходит дальше?
решение1
Мой TCP немного заржавел, но я думаю, что он работает следующим образом:
Когда хост B вызывает close()
и отправляет свой FIN
, порядковый номер на нем FIN
покажет хосту A, что он пропустил пакет от хоста B. Поэтому хост A не будет подтверждать пакет хоста B FIN
, он продолжит подтверждать последний сегмент TCP, который он успешно получил от хоста B. Это побудит хост B повторно передать отсутствующий пакет ACK
.
Таким образом, хост А не достигнет CLOSING
состояния, поскольку он не будет считать неисправное сообщение FIN
действительно полученным, пока не получит отсутствующее сообщение ACK
, которое ему предшествовало.