Одним словом, да, возможно, у вас есть ошибка на стороне, не являющейся инициатором закрытия. Это не имеет ничего общего с неблокирующими сокетами. Неблокирующие сокеты влияют только на взаимодействие между вашим приложением и его собственной операционной системой.
Важно понимать, что обе стороны должны прервать соединение с сокетом, чтобы состояние было должным образом очищено. Похоже, ваш сервер не закрывает свой конец сокета. Один из возможных сценариев:
- Сервер создает сокет прослушивания, связывает его и т. Д.
- Сервер звонков
accept
- Клиент звонит
connect
, создавая соединение (состояние TCP с обеих сторон переходит в ESTABLISHED
send
/ recv
/ send
/ recv
/ и т. Д. (Состояние все еще ESTABLISHED
)
- Клиент звонит
close
; клиентская ОС отправляет FIN
пакет на сервер (клиентская ОС перемещает состояние сокета в FIN_WAIT1
)
- Серверная ОС отправляет
ACK
для подтверждения FIN
клиентского компьютера (серверная ОС перемещает состояние сокета в CLOSE_WAIT
; клиентская ОС перемещает состояние сокета в FIN_WAIT2
)
- Сервер (программа) никогда не закрывает свой сокет, и, следовательно, серверная ОС никогда не отправляет
FIN
, поэтому клиентская ОС будет поддерживать сокет в состоянии FIN_WAIT2
. (Состояние сокета сервера указано в CLOSE_WAIT
)
Состояние сокета на стороне клиента может оставаться в состоянии FIN_WAIT2
в течение длительного времени или даже навсегда, в зависимости от реализации ОС. Например, в Linux есть настраиваемая переменная tcp_fin_timeout
, которая указывает, как долго в противном случае будет оставаться неактивное соединение в FIN_WAIT2
; но стандарт TCP не определяет время ожидания для FIN_WAIT2
. (Обратите внимание, что клиентская программа ничего об этом не знает. Она закрыла сокет, дескриптор файла сокета был уничтожен и сокет больше не доступен для него; все это обрабатывается операционной система.)
Если это именно то, что произошло, вы можете попробовать перезапустить серверную программу (потому что, когда вы завершаете процесс сервера, операционная система сервера автоматически закрывает все свои открытые файлы, и это приведет к отправке FIN
s на любой еще открытые розетки). Я думаю, вы увидите, что перезапуск сервера приводит к тому, что все эти сокеты на стороне клиента переходят в состояние TIME_WAIT
, где они останутся на короткое время, прежде чем исчезнут сами по себе. (Там - это механизм тайм-аута, указанный для TIME_WAIT
.)
См. Также диаграмму состояния TCP: