Причина, по которой вы получаете это, связана с природой протокола TCP: соединение находится в состоянии TIME-WAIT в конечном автомате TCP, описанном RFC793 . Диаграмма конечного автомата находится на странице 23 RFC793.
Интересный момент конечного автомата - это когда один конец (которого я назову «вами») захочет закрыть соединение - это известно как «активное закрытие», и в этом случае это то, что вы инициируете вызовами socket-close
. Я назову другой конец «их». Обычная последовательность событий для активного закрытия:
- вы отправляете им пакет FIN;
- они принимают ваш FIN и по очереди отправляют FIN;
- вы подтверждаете их FIN.
Теперь важно помнить, что любой из этих пакетов (их ACK и FIN обычно являются одним и тем же пакетом, и я думаю, что всегда) может быть потерян, и конечный автомат должен восстановиться отсюда.
Есть один особенно интересный пакет, который является последним ACK: он особенно интересен, потому что это последний отправленный пакет , что означает, что у вас нет возможности узнать, он достиг их .
Итак, рассмотрим ситуацию с обоих концов
С их конца : они отправили FIN и ждут вашего ACK для него , Теперь:
- либо ACK прибывает в должное время, и в этом случае они знают, что все свернуто, и они могут демонтировать все, что связано с соединением.
- или, после ожидания в установленное время ACK не приходит , поэтому они должны предположить, что либо их FIN потерян, либо ваш ACK на их FIN потерян, и поэтому они должны повторно отправить FIN и go вернуться к ожиданию ACK.
С вашего конца : вы получили их FIN и отправили последний ACK. Но вы понятия не имеете, дошел ли когда-нибудь до этого ACK. Таким образом, вы ждете в течение предписанного времени, чтобы дать им шанс понять, что ACK не получил их, и повторно отправить их FIN. Во время этого ожидания вы не можете разорвать соединение, потому что в любой момент вы можете получить еще один FIN.
Это состояние ожидания называется TIME-WAIT, и во время него конечная точка соединения не может быть повторно использована , И это проблема, с которой вы сталкиваетесь.
Вам нужно сидеть в TIME-WAIT вдвое больше максимального времени жизни сегмента (MSL): MSL - это то, как долго пакет может находиться в сети.
Существуют и другие состояния ожидания, которые могут возникать до времени ожидания, если ранние пакеты будут потеряны. Но TIME-WAIT является единственным, который всегда встречается.
TIME-WAIT часто называют TIME_WAIT из-за языков, которые не могут обрабатывать дефисы в именах.