В C я понял, что если мы закроем сокет, это означает, что сокет будет уничтожен и может быть использован позже.
Как насчет выключения? В описании сказано, что он закрывает половину дуплексного соединения с этим сокетом. Но будет ли этот сокет уничтожен как close
системный вызов?
c
sockets
networking
tshepang
источник
источник
Ответы:
Это объясняется в сетевом руководстве Биджа.
shutdown
это гибкий способ блокировать общение в одном или обоих направлениях. Когда второй параметр имеет значениеSHUT_RDWR
, он будет блокировать отправку и получение (какclose
). Тем не менее,close
это способ действительно уничтожить сокет.С помощью
shutdown
вы все равно сможете получать ожидающие данные, уже отправленные пэром (спасибо Джои Адамсу за то, что отметили это).источник
shutdown
оба направления, но это не такclose
, если вы сделалиFILE
ссылку на сокет, используяfdopen
. Если выclose
используете сокет, недавно открытому файлу может быть назначен тот же самый fd, и последующее использованиеFILE
будет считывать / записывать неправильное место, что может быть очень плохо. Если вы простоshutdown
, последующее использованиеFILE
просто выдаст ошибки, пока неfclose
будет вызвано.shutdown
: сигнализировать EOF одноранговому узлу и при этом иметь возможность получать ожидающие данные, которые отправил одноранговый узел.Ни один из существующих ответов не рассказывает людям о том, как
shutdown
и какclose
работает на уровне протокола TCP, поэтому стоит добавить это.Стандартное TCP-соединение завершается четырехсторонним завершением:
Тем не менее, существует еще один «эмерджентный» способ закрыть TCP-соединение:
В моем тесте с Wireshark, с параметрами сокета по умолчанию,
shutdown
отправляется пакет FIN на другой конец, но это все, что он делает. Пока другая сторона не отправит вам пакет FIN, вы все равно сможете получать данные. Как только это произойдет, выReceive
получите результат 0 размера. Так что, если вы первый, кто отключил «send», вы должны закрыть сокет, как только закончите получать данные.С другой стороны, если вы звоните,
close
когда соединение все еще активно (другая сторона все еще активна, и у вас также могут быть неотправленные данные в системном буфере), пакет RST будет отправлен на другую сторону. Это хорошо для ошибок. Например, если вы считаете, что другая сторона предоставила неверные данные или отказалась предоставить данные (атака DOS?), Вы можете сразу же закрыть сокет.Мое мнение о правилах будет:
shutdown
раньше,close
когда это возможноИдеальные реализации для SHUT_RD и SHUT_WR
Следующие не были проверены, доверяйте на свой страх и риск. Тем не менее, я считаю, что это разумный и практичный способ ведения дел.
Если стек TCP получает завершение только с SHUT_RD, он должен пометить это соединение как ожидаемое больше данных. Любые ожидающие и последующие
read
запросы (независимо от того, в каком потоке они находятся) будут возвращены с нулевым результатом. Тем не менее, соединение все еще активно и доступно - вы все еще можете получать данные OOB, например. Кроме того, ОС будет отбрасывать любые данные, которые она получает для этого подключения. Но это все, посылки не будут отправлены на другую сторону.Если стек TCP получает завершение только с SHUT_WR, он должен пометить это соединение, так как больше данных не может быть отправлено. Все ожидающие запросы на запись будут завершены, но последующие запросы на запись не будут выполнены. Кроме того, пакет FIN будет отправлен другой стороне, чтобы сообщить им, что у нас нет больше данных для отправки.
источник
shutdown()
установить соединение, и тогда оно больше не будет живым. У вас все еще есть дескриптор файла. Вы все еще можетеrecv()
из приемного буфера. И вам все равно нужно позвонить,close()
чтобы избавиться от дескриптора файла.Есть некоторые ограничения
close()
, которых можно избежать, если использоватьshutdown()
вместо них.close()
завершит оба направления на TCP-соединении. Иногда вы хотите сообщить другой конечной точке, что вы закончили отправку данных, но все же хотите получать данные.close()
уменьшает счетчик ссылок дескрипторов (поддерживается в элементе таблицы файлов и подсчитывает количество открытых в данный момент дескрипторов, которые ссылаются на файл / сокет) и не закрывает сокет / файл, если дескриптор не равен 0. Это означает, что если вы разветвляетесь, очистка происходит только после того, как счетчик ссылок упадет до 0. При этомshutdown()
можно инициировать нормальную последовательность закрытия TCP, игнорируя счетчик ссылок.Параметры следующие:
int how
возможно:SHUT_RD
или0
далее получает запрещеныSHUT_WR
или1
дальнейшие посылки запрещеныSHUT_RDWR
или2
далее отправлять и получать запрещеноисточник
Это может зависеть от платформы, я почему-то в этом сомневаюсь, но в любом случае лучшее объяснение, которое я видел, здесь, на этой странице msdn, где они объясняют о выключении, опциях задержки, закрытии сокета и общих последовательностях завершения соединения.
Таким образом, используйте shutdown, чтобы отправить последовательность выключений на уровне TCP, и используйте close, чтобы высвободить ресурсы, используемые структурами данных сокетов в вашем процессе. Если вы не выдавали явную последовательность выключения к тому времени, когда вы вызываете close, то она инициируется для вас.
источник
Я также добился успеха при использовании linux
shutdown()
из одной pthread, чтобы заставить другой pthread, заблокированный в данный момент,connect()
прервать работу раньше.В других операционных системах (по крайней мере, в OSX) я обнаружил, что вызова
close()
достаточно дляconnect()
сбоя.источник
«shutdown () на самом деле не закрывает файловый дескриптор - он просто меняет его удобство использования. Чтобы освободить дескриптор сокета, вам нужно использовать close ()». 1
источник
близко
Когда вы закончили использовать сокет, вы можете просто закрыть его файловый дескриптор с помощью close; Если все еще есть данные, ожидающие передачи по соединению, обычно закрыть пытается завершить эту передачу. Вы можете контролировать это поведение, используя опцию сокета SO_LINGER, чтобы указать период ожидания; см. Параметры сокета.
Неисправность
Вы также можете отключить только прием или передачу по соединению, вызвав завершение работы.
Функция отключения отключает подключение розетки. Его аргумент how указывает, какое действие нужно выполнить: 0 Прекратить получение данных для этого сокета. Если поступят дополнительные данные, отклоните их. 1 Прекратите пытаться передавать данные из этого сокета. Откажитесь от любых данных, ожидающих отправки. Прекратите искать подтверждение данных, уже отправленных; не передавайте его повторно, если оно потеряно. 2 Остановите прием и передачу.
Возвращаемое значение равно 0 в случае успеха и -1 при ошибке.
источник
в моем тесте.
close
отправит пакет fin и немедленно уничтожит fd, если сокет не используется совместно с другими процессамиshutdown
SHUT_RD , процесс может все еще получать данные из сокета, ноrecv
вернет 0, если буфер TCP пуст. После того, как узел отправит больше данных,recv
вернет данные снова.shutdown
SHUT_WR отправит пакет fin, чтобы указать, что дальнейшие отправки запрещены. узел может получить данные, но он получит 0, если его буфер TCP пустshutdown
SHUT_RDWR (равнозначно использованию SHUT_RD и SHUT_WR ) отправит первый пакет, если узел отправит больше данных.источник
close()
отправил RST на Linux вместо FIN.recv()
вернет данные снова», неверно. 2. Поведение, если одноранговый узел отправляет больше данных после,SHUT_RD
зависит от платформы.