Сокеты TCP: откат после тайм-аута

Это довольно общий вопрос о сокетах TCP. У меня есть настройка клиент-серверного приложения, в которой сообщения отправляются по сети через TCP. Реализация осуществляется через C++ POCO, однако вопрос не связан с конкретной технологией.

Сообщение может быть запросом (инициированным клиентом) или ответом (инициированным сервером).

Запрос имеет структуру:

Message Header
Request Header
Parameters

Ответ имеет структуру

Message Header
Response Header
Parameters

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

С обеих сторон у меня настроен тайм-аут чтения/отправки. Теперь интересно, как иметь чистую настройку на передаваемых данных после тайм-аута. Не знаю, как выразить это в правильных терминах, поэтому позвольте мне описать пример:

  1. Сервер S отправляет ответ клиенту (заголовок сообщения, заголовок ответа, параметры помещаются в поток)
  2. Клиент C частично получает заголовок сообщения (например, первые 4 байта из 12).
  3. После того, как эти 4 байта были получены, происходит тайм-аут приема
  4. На стороне клиента будет выброшено соответствующее исключение, прием будет остановлен.
  5. Клиент считает пакет недействительным.

Теперь проблема в том, что когда клиент пытается получить другой пакет, он может получить оставшуюся часть «старого» заголовка ответного сообщения. С точки зрения текущей обрабатываемой транзакции (отправить запрос/получить ответ) клиент получает мусор.

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

Так как же обычно обрабатываются такие ситуации? Есть ли какой-то шаблон дизайна/идиоматический способ решить эту проблему? Как такие ситуации обрабатываются в других протоколах на основе TCP, например. HTTP?

Во всех образцах TCP в сети я никогда не видел реализации, которая решает такие проблемы...

заранее спасибо


person mbue    schedule 21.08.2013    source источник
comment
Пожалуйста, оставьте мне комментарий, почему вопрос был отклонен :-/   -  person mbue    schedule 21.08.2013


Ответы (1)


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

Он получит остальную часть ошибочного сообщения, если вообще что-либо получит. Он не может получить ничего другого, а именно данные, которые были отправлены позже, не могут быть получены раньше или вместо данных, которые были отправлены ранее. Это надежный поток байтов. Вы можете закодировать соответственно.

связь должна продолжаться с «чистой настройкой», что означает, что ни один из партнеров по связи не будет пытаться отправить некоторые старые данные пакета

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

Таким образом, вам нужно либо закодировать свой клиент, чтобы он справлялся со всем потоком байтов по мере его поступления, либо, возможно, закрыть соединение по тайм-ауту и ​​начать заново.

person user207421    schedule 22.08.2013
comment
Большое спасибо EJP за ваше мнение. Мое текущее решение - перезапуск соединения. На второй итерации я попытаюсь обнаружить начало сообщения с префиксом и просто отбросить все, что было раньше. - person mbue; 22.08.2013