связь сервер — клиент

#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:

Похоже, что для вашего клиента есть четыре возможных результата:

  1. Сервер выполняет команду и отправляет обратно «ОК».
  2. Сервер испытывает проблему при выполнении команды и вместо этого отправляет обратно строку ошибки.
  3. Сервер завершает работу, аварийно завершает работу или иным образом отключается при попытке выполнить команду, и TCP-соединение закрывается.
  4. Сервер дает сбои и зависает при попытке выполнить команду или по какой-либо другой причине он никогда не отправляет обратно никакого ответа (но он сохраняет TCP-соединение открытым).

Первые три могут быть обработаны простым способом на клиенте. Чтобы справиться с четвертой проблемой, вам нужно было бы установить тайм-аут на стороне клиента — но тогда вы рискуете преждевременным истечением времени ожидания, когда на самом деле сервер просто медленно реагировал, а не был фактически сломан. Вероятно, лучше всего сделать время ожидания достаточно большим (например, 30 секунд?), а также убедиться, что ваш сервер надежен и не зависает. 🙂