Например, у нас есть клиент-серверное приложение. Если сервер пишет сообщение в сокете, а затем закрывает его до того, как клиент прочитает. Сможет ли клиент прочитать сообщение?
Какое отношение сокеты имеют к C++ или C? Сокеты — это интерфейс, к которому можно получить доступ, независимо от языка.
@ThomasMatthews Мой проект на C, поэтому я отметил C/C++, я не знал, работают ли сокеты по-другому на других языках
Кстати, C - это другой язык, чем C++. Например, в C++ есть шаблоны и std::string
. В языке C есть массивы символов, и у вас может быть переменная с именем «класс». Нет такого языка, как C/C++.
Насколько я понимаю, код сокета будет вести себя одинаково независимо от того, используете ли вы Java, Fortran или Visual Basic.
@ThomasMatthews C и C++ имеют общие библиотеки для сокетов
«Если сервер напишет сообщение в сокете, а затем закроет его до того, как клиент прочитает. Сможет ли клиент прочитать сообщение?»
да. Клиент получит данные, которые были отправлены до пакета FIN, закрывающего сокет.
Предполагая, что сервер изящно закрывает сокет, чтобы вообще создать FIN, то есть
@RemyLebeau Конечно. Если серверный процесс дает сбой или просто exit
s, или ОС на любом конце имеет ошибку, или кто-то выдергивает сетевой кабель, или испаряется достаточная промежуточная сетевая инфраструктура. И т. д. Тогда никто не может сделать никаких разумных предположений о том, что произойдет.
Что, если FIN опережает данные и первым достигает клиента/сервера. Гарантировано ли, что он все еще сможет читать?
@Chipster все TCP-пакеты имеют порядковый номер. Сетевой стек (обычно реализованный в ядре ОС) отвечает за доставку пакетов в приложение по порядку и задерживает доставку или запрашивает повторную передачу пакетов в зависимости от ситуации. С точки зрения приложений TCP-соединение представляет собой упорядоченный поток байтов, и оно никогда не увидит, что что-то поступает не по порядку. С UDP все иначе.
Это поведение зависит от реализации, в общем, вы не должны предполагать, что клиент может прочитать сообщение, close(2)
в руководстве по Linux говорится:
Be sure to use shutdown(2) to shut down all parts the connection before closing the socket.
Если вы хотите убедиться, что клиент прочитал это сообщение, сделайте так, чтобы этот клиент подтвердил это действие в протоколе вашего приложения.
Когда вы отправляете данные через сокет, а затем закрываете тот же сокет, нет никакой гарантии, что ядро очистило свои внутренние буферы в сети или даже могло бы это сделать (возможные проблемные сетевые условия).
«Когда вы отправляете данные через сокет, а затем закрываете тот же сокет, нет никакой гарантии, что ядро опустошило свои внутренние буферы в сеть» — нет, вы этого не знаете. Но это буду сделать. Он не просто отбрасывает невыполненные данные при закрытии.
Я не думаю, что это ответ на вопрос. Вопрос касается клиент-сервера, что подразумевает 2 разных процесса и дескриптора, используемых для сокетов, и этот ответ относится к блокировке в другом потоке (тот же процесс), в том же сокете.
Это не верно. Соединение останется внутри ядра и обеспечит опустошение буферов даже после закрытия сокета. Вы можете заблокировать свою программу на close()
, ожидая завершения соединения, используя опцию SO_LINGER.
Он отбросит невыполненные данные при закрытии, если не сможет их отправить, и вы получите сообщение об ошибке из close(2)
.
@Bitwize Чтобы уточнить, я не хотел ссылаться на весь цитируемый блоком текст, отредактировал свой ответ.
@LightnessRacesinOrbit Закрытие сокета не отключает поведение протокола TCP. Он будет повторять попытки до тех пор, пока не получит ACK или не сдастся, как обычно.
@lvella О да: D Это не будет FIN, пока он не очистит буфер и не получит все ACKd, я полагаю
@lvella Ты уверен в этом? Мне кажется, что просьба close(2)
означает, что вы хотите, чтобы системные ресурсы за файловым дескриптором были очищены. Не поделитесь ссылкой на такую информацию?
«возможные проблемные сетевые условия» применяются всегда. В этом отношении ничего особенного в close
нет. Если вы отправляете что-то, а никогда закрывает сокет, «возможные проблемные сетевые условия» могут помешать получателю получить данные.
Я бы предположил, что он освобождает ресурсы на определенном уровне, но базовый сетевой драйвер по-прежнему делает свое дело и управляет своими собственными ресурсами, как всегда.
Действительно, на странице руководства конкретно сказано, что когда ваш FD представляет файл, close
на самом деле не делает с файлом ничего волшебного. Вы просто закрываете ручку. Синхронизация/буферизация/и т. д. все еще происходит внизу.
@JesperJuhl Конечно, если это неправильно для линукс, пусть будет так. Я предпочитаю не слишком полагаться на поведение ядра в этом отношении или, скорее, решаю не зависеть от него, что может создать проблемы с переносимостью.
Конечно, мы все предполагаем, что это похоже на BSD close
. Я думаю, что это справедливое предположение, особенно потому, что все сокеты, которые я знаю, почти наверняка работают так.
@LeoLeBouter Да, я уверен, но, к сожалению, у меня нет ссылки. Я не думаю, что это где-то указано явно, но вы можете склеить части вместе: сокеты — это интерфейс POSIX для любого типа сети, включая TCP/IP, сокеты Unix, X25 и т. д. close()
является частью этого интерфейса, и отключает сокет. Изменение ожидаемого поведения TCP/IP было бы очень странным исключением для реализации.
Укажите операционную систему и интерфейс сокетов.