socket.shutdown против socket.close - PullRequest
115 голосов
/ 03 января 2009

Недавно я увидел немного кода, который выглядел следующим образом (разумеется, sock был объектом сокета):

sock.shutdown(socket.SHUT_RDWR)
sock.close()

Какова цель вызова завершения работы сокета и последующего его закрытия? Если это имеет значение, этот сокет используется для неблокирующего ввода-вывода.

Ответы [ 7 ]

220 голосов
/ 01 марта 2009

Вызов close и shutdown оказывают два разных эффекта на базовый сокет.

Первое, на что следует обратить внимание, это то, что сокет является ресурсом в базовой ОС, и несколько процессов могут иметь дескриптор для одного и того же базового сокета.

Когда вы вызываете close, он уменьшает количество дескрипторов на единицу, а если количество дескрипторов достигло нуля, тогда сокет и связанное с ним соединение проходят через обычную процедуру закрытия (эффективно отправляя FIN / EOF равноправному узлу) и сокет освобожден.

Здесь следует обратить внимание на то, что если счетчик дескрипторов не достигает нуля, поскольку другой процесс все еще имеет дескриптор сокета, то соединение не закрывается и сокет не освобождается.

С другой стороны, вызов shutdown для чтения и записи закрывает базовое соединение и отправляет FIN / EOF одноранговому узлу независимо от того, сколько процессов имеет дескрипторы для сокета. Тем не менее, не освобождает сокет, и вам все равно необходимо после этого вызвать close.

35 голосов
/ 04 января 2009

Вот одно объяснение :

Как только сокет больше не требуется, вызывающая программа может отбросить сокет, применяя подпрограмму close в дескриптор сокета. Если надежный сокет доставки имеет данные связано с этим, когда близкий берет место, система продолжает попытки Обмен данными. Тем не менее, если данные все еще не доставлено, система сбрасывает данные. Если приложение Программа не имеет смысла для каких-либо ожидающих данные, он может использовать выключение подпрограмма на сокете до закрывая его.

18 голосов
/ 04 января 2009

Объяснение выключения и закрытия: Изящное выключение (msdn)

Завершение работы (в вашем случае) означает, что на другом конце соединения больше нет намерений читать или записывать данные в сокет. Затем close освобождает любую память, связанную с сокетом.

Пропуск выключения может привести к задержке сокета в стеке ОС до тех пор, пока соединение не будет закрыто изящно.

ИМО, названия «выключение» и «закрытие» вводят в заблуждение, «закрытие» и «уничтожение» подчеркивают их различия.

7 голосов
/ 25 сентября 2013

упоминается прямо в HOWTO по программированию сокетов ( py2 / py3 )

Разъединение

Строго говоря, вы должны использовать shutdown в сокете, прежде чем close его. shutdown является рекомендацией для сокета на другом конце. В зависимости от аргумента, который вы передаете, это может означать: « Я больше не буду отправлять, но я все равно буду слушать » или « Я не слушаю, хорошее избавление! 1018 *». Однако большинство библиотек сокетов настолько привыкли к программистам, которые пренебрегают этим этикетом, что обычно close совпадает с shutdown(); close(). Поэтому в большинстве случаев явное отключение не требуется.

...

5 голосов
/ 09 апреля 2010

Разве этот код неверен?

Вызов close сразу после вызова shutdown может заставить ядро ​​в любом случае сбросить все исходящие буферы.

Согласно http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable нужно ждать между выключением и закрытием, пока чтение не вернет 0.

4 голосов
/ 04 января 2009

есть несколько вариантов выключения: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx. * nix похож.

2 голосов
/ 31 марта 2010

Shutdown (1), заставляет сокет no отправлять больше данных

Это полезно в

1 - Очистка буфера

2- Странное обнаружение ошибок

3- Безопасная охрана

Позвольте мне объяснить больше, когда вы отправляете данные из А в Б, это не гарантируется отправлено в B, гарантированно будет отправлено только в буфер A os, который в свою очередь отправляет его в буфер B os

Таким образом, вызывая shutdown (1) для A, вы очищаете буфер A и возникает ошибка если буфер не пустой, т.е. данные еще не были отправлены одноранговому узлу

Как бы то ни было, это необратимо, так что вы можете сделать это после того, как полностью послал все ваши данные, и вы хотите быть уверены, что это по крайней мере в одноранговой ОС буфер

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...