socket.shutdown vs socket.close


122

Нещодавно я побачив трохи коду, який виглядав приблизно так (але, звичайно, шкарпетка є об'єктом socket):

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

Яка саме мета виклику відключення розетки та її закриття? Якщо це має значення, ця розетка використовується для незаблокування вводу-виводу.

Відповіді:


38

Ось одне пояснення :

Після того, як сокет більше не потрібен, виклична програма може відкинути сокет, застосувавши до дескриптора сокета близьку підпрограму. Якщо надійний сокет доставки містить дані, пов'язані з ним, коли відбувається закриття, система продовжує намагатися перенести дані. Однак якщо дані все ще недоставлені, система відкидає дані. Якщо прикладна програма не використовує жодних відкладених даних, вона може використовувати підпрограму відключення в сокеті перед її закриттям.


241

Виклик closeі shutdownмає два різні ефекти на нижній розетці.

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

Якщо ви називаєте closeце декрементацією, кількість оброблюваних ручок на одиницю, і якщо кількість ручки досягає нуля, то розетка та пов'язане з цим з'єднання проходять через звичайну процедуру закриття (ефективно відправляючи FIN / EOF на одноранговий), і сокет розміщується.

На що тут слід звернути увагу, це те, що якщо кількість ручки не досягає нуля, оскільки інший процес все ще має ручку до сокета, то з'єднання не закрите і розетка не розміщена.

З іншого боку, виклик shutdownчитання та запису закриває базове з'єднання та надсилає FIN / EOF однорангові незалежно від того, скільки процесів має ручки до сокета. Однак це не роз'єднує розетку, і вам все одно потрібно зателефонувати після закриття.


чудова відповідь, я ніколи не намагався дізнатися, що shutdown()робить :)
Метт Столяр

2
Чи може вимкнення () для читання змусити його відправити FIN-пакет? тобто вимкнення (sock_fd, 1);
ernesto

Було б розумно завжди телефонувати .shutdown()і на наступному рядку .close()? Або між ними має бути затримка?
Люк

@Luc Повністю залежить від того, що ти робиш.
Роберт С. Барнс

2
@Luc Тоді просто закрити це добре, поки жоден інший процес не має ручки до сокета.
Роберт С. Барнс

17

Пояснення відключення та закриття: витончене вимкнення (msdn)

Вимкнення (у вашому випадку) вказує на інший кінець з'єднання, більше немає наміру читати або записувати в сокет. Потім закрийте звільнення будь-якої пам'яті, пов'язаної з сокетом.

Якщо вимкнути відключення, розетка може затриматися в стеці ОС, поки з'єднання не буде належним чином закрито.

ІМО назви "закриття" та "закрити" вводять в оману, "закривають" та "знищують" підкреслюють їх відмінності.


Це не вказує на інший кінець, що немає жодного наміру читати. Вимкнення для читання нічого не надсилає одноліткові.
Маркіз Лорн

7

згадується прямо в програмуванні Socket HOWTO ( py2 / py3 )

Відключення

Власне кажучи, ви повинні використовувати його shutdownна розетці перед closeцим. shutdownЄ консультативним до гнізда на іншому кінці. Залежно від аргументу, який ви передаєте, це може означати: " Я більше не збираюся надсилати, але все одно буду слухати ", або " Я не слухаю, хороша загадка! ”. Однак більшість бібліотек сокетів настільки використовуються для програмістів, які нехтують використанням цього фрагменту етикету, що, звичайно, a closeє таким же, як shutdown(); close(). Тому в більшості ситуацій явне відключення не потрібно.

...


Ця інформація не вірна. Вимкнути розетку для запису потрібно лише в тому випадку, якщо (1) ви роздрібнили процес і напевно хочете відправити FIN зараз або (2) ви залучаєте до взаємного протоколу зчитування до EOS таким чином, що обидва колеги закриваються в той самий час. Інакше close()достатньо. Документацію Python слід виправити.
Маркіз Лорн

4

Хіба цей код вище невірний?

Виклик закриття безпосередньо після виклику відключення може змусити ядро ​​все одно відкинути всі вихідні буфери.

Відповідно до http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable потрібно чекати між вимкненням та закрити, поки читання не поверне 0.


Неправильно. Ядро відкидає вихідні буфери лише у тому випадку, коли з'єднання було скинуто, що може статися, якщо локальний додаток не прочитав усі очікувані вхідні дані, які вже надійшли, або якщо одноранговець заблукав із SO_LINGER, чого вони не повинні робити . Немає потреби спати, навіть навіть не викликати відключення перед закриттям. З цього питання існує багато дезінформації.
Маркіз Лорн


1

Вимкнення (1), змушує сокет не надсилати більше даних

Це корисно

1- Буфер промивання

2- Дивне виявлення помилок

3- Безпечна охорона

Поясню докладніше, коли ви надсилаєте дані від A до B, він не гарантовано надсилається до B, він гарантовано лише надсилається до буфера A os, який, у свою чергу, надсилає його до буфера B os

Отже, зателефонувавши до вимкнення (1) на A, ви змиваєте буфер A і виникає помилка, якщо буфер не порожній, тобто дані ще не надіслані однорангові

Однак це незворотно, тому ви можете це зробити після того, як ви повністю надіслали всі свої дані і хочете бути впевнені, що це якнайменше в буфері однорангових ОС


Вимкнення не змушує змити. Буферна ситуація не змінюється. І якщо буфер не порожній, помилка не виникає. ПІН лише зазначається за очікуваними даними. Відповідь абсолютно невірна.
Маркіз Лорн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.