#c #sockets
#c #сокеты
Вопрос:
Я пишу сетевую программу на C, в которой клиент отправляет блок данных на сервер, и я хочу убедиться, что все данные были прочитаны сервером, прежде чем я закрою сокет со стороны клиента. Я думал отправить специальный символ ‘ok’ обратно с сервера клиенту, но я думаю, что если во время выполнения серверной программы произойдет что-то неправильное и сервер закроет канал со своей стороны (например, сбой системного вызова read), клиент будет ждать системного вызова read для чего-то, что никогда не произойдет. Есть идеи о том, как я могу это решить?
спасибо, Никос
Ответ №1:
Я хочу убедиться, что все данные были прочитаны сервером b *, прежде чем я закрою сокет со стороны клиента*.
Если вы используете TCP, учтите следующее: после отправки данных, даже если вы закроете сокет / выйдете из программы, стек TCP продолжит делать все возможное для их отправки.
Как только вы send
/ write
передадите данные, они уйдут из ваших рук. Оно копируется в буфер ядра и отправляется некоторое время спустя. За кулисами (где-то глубоко внутри netinet
) соединение не закрывается до тех пор, пока все отправленные данные не будут подтверждены / соединение разорвано по другим причинам.
Комментарии:
1. итак, вы предполагаете, что мне вообще не нужно реализовывать эту проверку (специальный признак подтверждения, отправленный обратно с сервера), если я использую TCP?
2. @nikos Это то, что я предлагаю. Не включайте
ACK
данныеTCP
, это делает это лучше, чем программисты.3. Ах, но вы никогда не говорили, что вам все равно, если данных не будет там к моменту, когда вы их закроете 😉 Было бы лучше переформулировать вопрос на что-то вроде «будут ли отправляться неполученные TCP-данные, записанные в сокет, даже после того, как я закрою сокет».
Ответ №2:
Предлагаемая вами реализация кажется мне прекрасной — если что-то не так, это исключительный случай — чтобы перехватить это, вам нужно использовать тайм-аут при вызове read.
Ответ №3:
Внедрите тайм-аут в клиенте. Подождите некоторое настраиваемое / разумное количество времени для ответа от сервера. Если этот период времени истечет, действуйте соответствующим образом.
Ответ №4:
протокол чередования битов — это способ решить эту проблему. существуют разные способы реализовать это.
Когда A отправляет сообщение, оно непрерывно отправляет его повторно с тем же порядковым номером, пока не получит подтверждение от B, содержащее тот же порядковый номер. Когда это происходит, A дополняет (переворачивает) порядковый номер и начинает передачу следующего сообщения.
Комментарии:
1. Серьезно? Зачем накладывать такой протокол поверх чрезвычайно сложного TCP? Даже в той паршивой книге Таненбаума говорится, что протокол чередования битов имеет множество проблем.
2. tcp уже гарантирует рукопожатие, как уже сказал cnicutar. так что игнорируйте мой ответ 😉
Ответ №5:
Не нужно беспокоиться о том, когда закрывать сокет на стороне вашего клиента. Пока данные записаны в сокет, вы можете закрыть его в любое время после этого. @cnicutar дает хорошее объяснение этому в своем ответе.
Что касается специальных символов подтверждения от вашего сервера обратно клиенту, вам не нужно беспокоиться об этом с TCP. Однако вы можете захотеть изменить свой блок данных таким образом, чтобы он включал заголовок, указывающий, сколько в нем данных. Например, первые 4 байта блока данных могут быть полем длины, указывающим, сколько еще байтов имеется. Сервер может прочитать первые 4 байта, а затем узнать, сколько еще байтов нужно прочитать. Связь по протоколу TCP обычно имеет что-то вроде этого.
Ответ №6:
Похоже, что для вашего клиента есть четыре возможных результата:
- Сервер выполняет команду и отправляет обратно «ОК».
- Сервер испытывает проблему при выполнении команды и вместо этого отправляет обратно строку ошибки.
- Сервер завершает работу, аварийно завершает работу или иным образом отключается при попытке выполнить команду, и TCP-соединение закрывается.
- Сервер дает сбои и зависает при попытке выполнить команду или по какой-либо другой причине он никогда не отправляет обратно никакого ответа (но он сохраняет TCP-соединение открытым).
Первые три могут быть обработаны простым способом на клиенте. Чтобы справиться с четвертой проблемой, вам нужно было бы установить тайм-аут на стороне клиента — но тогда вы рискуете преждевременным истечением времени ожидания, когда на самом деле сервер просто медленно реагировал, а не был фактически сломан. Вероятно, лучше всего сделать время ожидания достаточно большим (например, 30 секунд?), а также убедиться, что ваш сервер надежен и не зависает. 🙂