AN003. Задержки при открытии DS TCP-соединения с ПК

О чём эта рекомендация по применению

Некоторые наши клиенты замечали, что иногда DS устанавливает TCP-соединение с ПК очень долго. Похоже, что ПК игнорирует запрос на соединение. Чаще всего эта проблема возникает, когда DS пытается «переподключиться» после внезапной перезагрузки (например, из-за пропадания питания). В этой рекомендации объясняется, почему так происходит и что можно сделать.

Содержание:

  • Как возникает задержка соединения
  • Режим «connect immediately» (соединяться сразу): DS сам занимается переподключением
  • Модемные команды и линия DTR для контроля состояния соединения и его «восстановления»

Как возникает задержка соединения

Задержка связана с тем, как «TCP-стек» на ПК обрабатывает существующие TCP-соединения. Покажем это на примере одного частого сценария обмена:

  • DS устанавливает TCP-соединение с ПК (например, потому что ему нужно отправить последовательные данные). Соединение принимается сразу. ПК идентифицирует это соединение по комбинации трёх параметров: IP удалённого хоста (то есть IP-адрес DS), порт удалённого хоста (то есть номер порта на DS, с которого установлено это соединение, по умолчанию 10001) и локальный порт на ПК, на который установлено соединение (то есть «слушающий» порт вашего приложения или VSP).
  • DS внезапно перезагружается, например из-за пропадания питания. ПК об этом не знает и считает, что это TCP-соединение всё ещё активно.
  • DS снова включается и пытается соединиться с ПК. Он опять пытается открыть соединение с порта 10001. ПК отвечает «ACK», как на обычный пакет данных. По сути, ПК просто игнорирует эту попытку соединения. Должно пройти много времени, прежде чем ПК поймёт, что это соединение уже мертво.
  • DS замечает, что ПК не ответил на запрос соединения, и отправляет пакет «RST», чтобы сбросить соединение. Одновременно DS отбрасывает данные, которые собирался отправить на ПК, и переходит в состояние «IDLE».
  • Когда DS получает новые последовательные данные, он снова пытается установить соединение. На этот раз порт-источник на DS - 10002, а не 10001. Дело в том, что порт-источник, с которого DS устанавливает TCP-соединение, увеличивается с каждой попыткой (это нормально, ПК делает то же самое).
  • ПК получает новую попытку соединения и воспринимает её как совершенно новое соединение. Это происходит потому, что в уникальной комбинации IP источника + порт источника + порт назначения теперь кое-что отличается: изменился номер порта источника. Поэтому ПК сразу принимает новое соединение.

Следующий сетевой журнал, снятый программой-сниффером WinDUMP, иллюстрирует описанный сценарий. DS имеет адрес 192.168.100.97, ПК - 192.168.100.90.

==========

*** DS пытается соединиться с ПК ***

192.168.100.97.10001 > 192.168.100.90.1002: S 640000:640000(0) win 1024 <mss 255> (DF)

192.168.100.90.1002 > 192.168.100.97.10001: S 10461646:10461646(0) ack 640001 win 8415 <mss 1460> (DF)

192.168.100.97.10001 > 192.168.100.90.1002: . ack 1 win 1024 (DF)

*** Соединение установлено ***

*** DS внезапно перезагружается ***

*** DS снова пытается установить соединение ***

192.168.100.97.10001 > 192.168.100.90.1002: S 256000:256000(0) win 1024 <mss 255> (DF)

*** ПК отвечает ACK, что неверно, поэтому DS сбрасывает эту попытку соединения и отбрасывает данные ***

192.168.100.90.1002 > 192.168.100.97.10001: . ack 1 win 8415 (DF)

192.168.100.97.10001 > 192.168.100.90.1002: R 640001:640001(0) win 8415 (DF)

*** DS снова пытается соединиться, на этот раз с другого порта, и соединение принимается ***

192.168.100.97.10002 > 192.168.100.90.1002: S 640000:640000(0) win 1024 <mss 255> (DF)

192.168.100.90.1002 > 192.168.100.97.10002: S 10470652:10470652(0) ack 640001 win 8415 <mss 1460> (DF)

192.168.100.97.10002 > 192.168.100.90.1002: . ack 1 win 1024 (DF)

==========

Итог: первая попытка соединения со стороны DS после внезапной перезагрузки может не удаться. Если ваше последовательное устройство отправляет всего несколько байт и ждёт установления TCP-соединения, этого может так и не произойти. Последовательному устройству нужно повторно отправить те же данные через некоторое время - только тогда ПК, возможно, наконец примет TCP-соединение.

Ускорить процесс и не дать ПК задерживать соединение можно двумя способами.

Режим «connect immediately» (соединяться сразу): DS сам занимается переподключением

Установите параметр Connection Mode (CM) в 0 (connect immediately) - тогда DS будет бесконечно пытаться соединиться, пока не добьётся успеха. Так вашему последовательному устройству не придётся повторно отправлять данные, чтобы соединение было установлено. В большинстве случаев соединение будет готово.

Модемные команды и линия DTR для контроля состояния соединения и его «восстановления»

Модемные команды (официально - параметры и инструкции последовательной стороны) позволяют вашему последовательному устройству следить за состоянием соединения и управлять его установлением и разрывом. Вместо того чтобы отправлять последовательные данные и надеяться, что они пройдут, можно сначала убедиться, что соединение действительно установлено.

Вот краткое описание того, как это может работать:

  • Сначала ваше последовательное устройство переводит DS в режим последовательного программирования.
  • Затем последовательное устройство инструкцией Establish Connection (CE) запускает на DS процедуру установления соединения.
  • После этого последовательное устройство проверяет результат командой Echo (X) (флаг c в ответе). Если соединение не установилось достаточно быстро и флаг c неожиданно вернулся в «*», последовательное устройство может заключить, что DS вернулся в режим ожидания, потому что ПК не ответил на запрос установления соединения.
  • Тогда последовательное устройство может быстро выдать ещё одну инструкцию Establish Connection (CE) и снова следить за состоянием соединения командой Echo (X).
  • Когда команда Echo покажет, что соединение установлено (флаг c="C"), последовательное устройство командой Logout (O) выводит DS из режима последовательного программирования. После этого можно начинать обмен данными.

Эта процедура, хотя и кажется длинной, занимает лишь доли секунды.

Остаётся вопрос: как обнаружить разрыв соединения в «обычном режиме». Действительно, пока DS находится в режиме последовательного программирования, состояние соединения можно проверить в любой момент командой Echo . Но как быть, когда DS находится в режиме передачи данных и команду Echo выдать нельзя?

Для этого нужно установить параметр DTR Mode (DM) в 1 (состояние соединения). В этом случае линия DTR на DS показывает, установлено сетевое соединение или нет. Как только линия «упадёт», последовательное устройство узнает, что с соединением что-то случилось. Тогда оно должно перевести DS в режим последовательного программирования и «восстановить» соединение с помощью модемных команд.