Требуется ли подтверждение при использовании send () / recv () Winsock? - PullRequest
3 голосов
/ 12 июня 2011

Используя Winsock, C ++, я отправляю и получаю данные с помощью send () / recv () , TCP-соединение.Я хочу быть уверен, что данные были доставлены другой стороне, и задаюсь вопросом, не рекомендуется ли отправить обратно какое-либо подтверждающее сообщение после (если) получения данных с помощью recv .

ЗдесьЕсть две возможности, и, пожалуйста, посоветуйте, куда идти:

  1. Если send возвращает размер переданного буфера, предположим, что данные были доставлены по крайней мере до recv функция на другой стороне провода.Когда я говорю «по крайней мере», я имею в виду, даже если recv терпит неудачу там (например, из-за недостатка буфера и т. Д.), Мне все равно, я просто хочу быть уверен, что сделалсерверная часть работы правильно - я отправил данные полностью (т.е. данные дошли до другой машины).

  2. Использовать дополнительное подтверждение: после получения данных с помощью recv отправить назад некоторый идентификатор принятого пакета (часть заголовка каждой отправленной информации), сигнализируя об успешной операции приема этого пакета.Если я не получаю такого «сообщения подтверждения» через некоторое время, верните код ошибки из функции отправителя.

Второй ответ выглядит более безопасным, но я не хочу усложнятьпротокол передачи, если он избыточен.Также обратите внимание, что я говорю о TCP-соединении (которое само по себе безопаснее, чем UDP).

Существуют ли другие механизмы (может быть, некоторые другие API-интерфейсы? Может быть, WSARecv () / WSASend () работает по-другому?) Чтобы гарантировать, что данные были доставлены в функцию recv на другой стороне?

Если вы порекомендуете второй способ, не могли бы вы дать мне кодфрагмент, который позволяет мне использовать recv с таймаутом для получения подтверждения? recv является операцией блокировки, поэтому она будет зависать вечно, если предыдущая попытка отправки не удалась (другая сторона не была уведомлена).Есть ли простой способ использования recv с тайм-аутом (без создания отдельного потока каждый раз, который, вероятно, будет избыточным для каждой операции send ).

Такжеобъем данных, которые я передаю функции send , может быть довольно большим (несколько мегабайт), так как выбрать тайм-аут для «сообщения подтверждения»?Может быть, мне следует «разделить» большие буферы и использовать несколько send вызовов?Я думаю, что это будет довольно сложно, пожалуйста, совет!

РЕДАКТИРОВАТЬ: ОК, вы, люди, предлагаете, что стек TCP / IP будет обрабатывать его (т. Е. Ручное подтверждение не требуется), но это то, что я нашелна странице MSDN: «Успешное завершение функции send не означает, что данные были успешно доставлены и получены получателю. Эта функция только указывает на то, что данные были успешно отправлены».Поэтому, даже если механизм TCP имеет возможность обеспечить доставку данных, я не могу получить этот статус (успешно или нет) с помощью функции send () или любой другой функции Winsock, которую я знаю.Знаете ли вы какой-нибудь способ получения статуса из уровня TCP?Опять же - возвращаемого значения функции send () кажется недостаточно!

========================================================

РЕДАКТИРОВАТЬ 2: ОК, я думаю, мы согласны с тем, что, хотя протокол TCP учитывает обработку ошибок, когда что-то идет не так, функция Winsock send () не способна сообщать об ошибках ( просто потому, что он возвращается до начала фактической передачи данных сетевым драйвером). Итак, вот вопрос на миллион долларов: гарантирует ли функция Winsock send () по крайней мере, что другие пакеты не будут доставлены другой стороне, пока не будет текущий пакет? Другими словами, если отправка не удалась из-за сбоя в сети (но не сообщается send () call), а затем сбой сети будет исправлен до следующего вызова send () будет работать со следующей порцией данных, будет ли гарантировано, что предыдущий пакет (который не был обработан, но не сообщен send () ) будет доставлен до следующего пакета? Другими словами, есть ли вероятность того, что одна конкретная функция send () завершится сбоем "без вывода сообщений", так что последующие вызовы send () будут выполнены успешно, но первый пакет будет потерян? ОПЯТЬ - я говорю не на уровне TCP, я говорю на уровне Winsock API!

Ответы [ 4 ]

3 голосов
/ 12 июня 2011

Существующие здесь ответы в основном правильные: если вы используете TCP, вам действительно не нужно беспокоиться о надежной доставке ваших пакетов вашему пиру.

Но это опасное представление для некоторых системы, в которых целостность данных должна быть выведена на следующий уровень: требование аудита общих критериев FAU_STG.4.1 требует способности предотвращать события, подлежащие аудиту , если в журнале аудита может возникнуть потеря записей аудита.(Например, демон ведения журнала аудита Linux auditd(8) может быть настроен для перевода компьютера в однопользовательский режим или полной остановки системы, когда для журналов аудита больше нет места.) Журналы аудита из удаленных систем, вероятно, должныподдерживается до тех пор, пока не будет известно , что они были успешно записаны на централизованные серверы журналов.

Финансовые транзакции, вероятно, лучше всего обрабатывать с использованием более надежного протокола, чем простой протокол TCP - кредитование или дебетованиеучетные записи лучше всего обрабатывать с помощью многоэтапного протокола, чтобы обеспечить доступность средств, выполнить транзакцию, а затем сообщить результат транзакции в точку отправления.

TCP позволяет почти гигабайт данных.полетные данные между двумя пирами (в экстремальных условиях);в зависимости от требований вашего приложения вам может потребоваться сохранить эти данные на стороне отправляющего , пока вы не получите положительное подтверждение от вашего партнера, что данные были обработаны правильно.

К счастью, большинствоприложения не так критичны;потеря мегабайта данных здесь или там вниз по сокету, который сообщает о закрытом соединении в какой-то момент «в будущем», действительно не страшна - мы просто повторяем наш HTTP-запрос или повторяем попытку SFTP-соединения.

Обновление

Сокет будет принимать только достаточное количество данных для заполнения доступного окна .Размер окна согласовывается между двумя узлами во время сеанса рукопожатия.Таким образом, ваши звонки на send() начнут блокироваться, когда окно сокета заполнится.(ОС может продолжать позволять вам добавлять данные и во внутренние буферы, но в какой-то момент записи будут блокироваться.) Если узел разрывает соединение с сообщением RST или ICMP Unreachable, future вызов send() вернет значение ошибки для сброса соединения или Broken Pipe.

Update 2

I'mне говорю на уровне TCP, я говорю на уровне Winsock API

Это может быть источником путаницы.send() не имеет другого выбора, кроме как придерживаться поведения TCP при использовании с TCP.

TCP гарантирует надежную доставку по порядку потока байтов в той степени, в которой могут быть доставлены пакеты.(См. Комментарий @ Ганса о том, как пони и неосторожные люди пинают шнуры питания.) Программа для сверстников будет видеть байты в том порядке, в котором они были отправлены.(Хорошо, хорошо, TCP также имеет внеполосную срочную доставку пакетов, но на самом деле я не видел приложений, которые его используют. Используя OOB-пакеты, вы можете получить некоторыеданные вне строки. Забудьте, что я упоминал об этом.)

Если удаленная программа получает байт, отправленный в поток TCP, она также надежно получила все предыдущие байты.(Ну, есть целые классы атак воспроизведения , которые объединяют легитимные и поддельные пакеты для удаленного узла, но это становится все труднее в системах с рандомизированными начальными порядковыми номерами. Если это в вашей модели угрозы, выследует использовать TLS поверх TCP для предоставления криптографически достоверной информации, которая может быть взломана. Но TLS не может обеспечить лучшее уведомление о доставке для каждого пакета.)

3 голосов
/ 12 июня 2011

Почему вы не доверяете своему стеку TCP / IP, чтобы гарантировать доставку. В конце концов, в этом весь смысл использования TCP вместо UDP.

1 голос
/ 12 июня 2011

Если вы используете UDP и вам небезразличны данные, которые фактически принимаются другой стороной, вам НУЖНО использовать ACK, но если вам не нужна скорость UDP, вам следует использовать TCP, поскольку он выполняет ACK для вас.

0 голосов
/ 12 июня 2011

Я думаю, вы слишком усложняете ситуацию, доверяете своему программному стеку TCP / IP и надежной доставке, которую он предлагает.TCP-сокеты работают с потоками данных, а не с пакетами.Также один звонок на send не гарантирует один звонок на recv.

...