Вопрос:
В настоящее время я работаю над компилятором server + client на python, и я использую TCP-сокеты. Из сетевых классов я знаю, что TCP-соединение должно быть закрыто шаг за шагом, сначала одна сторона посылает сигнал, что он хочет закрыть соединение и ждет подтверждения, а другая сторона делает то же самое. После этого гнездо можно безопасно закрыть.
Я видел в документации документации python socket.shutdown(flag), но я не вижу, как это можно использовать в этом стандартном методе, теоретически закрывая TCP-сокет. Насколько я знаю, он просто блокирует чтение, письмо или и то, и другое.
Какой лучший, самый правильный способ закрыть TCP-сокет в python? Существуют ли стандартные функции для закрытия сигналов или я должен сам их реализовать?
Лучший ответ:
Согласно документации на python, которая гласит:
Строго говоря, вы должны использовать shutdown в сокете, прежде чем закрыть его. Выключение – это рекомендация к разъему на другом конце. В зависимости от аргумента, который вы передаете, это может означать, что “я больше не буду отправлять, но я все еще слушаю”, или “Я не слушаю, хорошее избавление!”. Однако большинство библиотек сокетов используются для программистов, пренебрегая использованием этой этикетки, которая обычно близка к тому же, что и shutdown(); Закрыть(). Поэтому в большинстве ситуаций явное закрытие не требуется.
Я думаю, что самый правильный способ закрыть TCP-соединение – это использовать shutdown перед закрытием соединения, потому что close не является атомарным! Это может привести к некоторым ошибкам. Предположим, вы используете close функцию без shutdown и данные не отправлялись на сервер правильно, в то же время python закрывает соединение, а сервер не может ответить клиенту, теперь сокет на другом конце может зависать бесконечно.
Ответ №1
выключение полезно, когда вы должны сигнализировать удаленному клиенту о том, что больше не отправляются данные. В параметре shutdown() вы можете указать, какой полуканальный канал вы хотите закрыть.
Чаще всего вы хотите закрыть полуканал TX, вызывая выключение (1). На уровне TCP он отправляет пакет FIN, а удаленный конец получает 0 байтов, если блокирует чтение(), но удаленный конец все равно может отправить данные обратно, поскольку полуканат RX все еще открыт.
Некоторые протоколы приложений используют это, чтобы сигнализировать о завершении сообщения. Некоторые другие протоколы обнаруживают МНВ на основе самих данных. Например, в интерактивном протоколе (где сообщения обмениваются много раз), возможно, не будет возможности или необходимости закрыть половинный канал.
В HTTP, shutdown (1) – это один из методов, который клиент может использовать для оповещения о завершении HTTP-запроса. Но сам протокол HTTP включает данные, которые позволяют определить, где заканчивается запрос, поэтому HTTP-соединения с несколькими запросами все еще возможны.
Я не думаю, что вызов shutdown() перед закрытием() всегда необходим, если только вам не нужно явно закрывать половинный канал. Если вы хотите прекратить все общение, закройте() это тоже. Вызов shutdown() и забывание вызвать close() хуже, потому что ресурсы дескриптора файла не освобождаются.
Из Википедии: “В системах SVR4 использование функции close() может отбрасывать данные. В этих системах может потребоваться использование shutdown() или SO_LINGER, чтобы гарантировать доставку всех данных”. Это означает, что если у вас есть выдающиеся данные в выходном буфере, функция close() может немедленно удалить эти данные в системе SVR4. Системы на базе Linux, BSD и BSD, такие как Apple, не являются SVR4 и будут пытаться полностью отправить выходной буфер после закрытия(). Я не уверен, что в настоящее время какой-либо крупный коммерческий UNIX по-прежнему является SVR4.
Снова используя HTTP в качестве примера, HTTP-клиент, работающий на SVR4, не потеряет данные с помощью функции close(), потому что он будет поддерживать соединение открытым после запроса, чтобы получить ответ. HTTP-сервер под SVR должен быть более осторожным, вызывая shutdown (2) до закрытия() после отправки всего ответа, потому что ответ будет частично в выходном буфере.