C # синхронный клиент TCP сокет необъяснимые пропущенные данные - PullRequest
1 голос
/ 28 сентября 2011

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

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

Кроме того, всякий раз, когда запрос на чтение отправляется на последовательное устройство, его внутренний указатель будет увеличиваться до следующего фрагмента данных, как только ответ будет отправлен.Последовательное устройство не будет знать, все ли в порядке мобильное соединениеесли ответ не вернется полностью к серверу, он все равно будет увеличивать свой внутренний указатель.

Другими словами, используйте следующий сценарий:

  1. Сервер отправляет Modbusзапрос на чтение по TCP.
  2. Маршрутизатор получает запрос и передает его на последовательное устройство.
  3. Последовательное устройство отвечает на маршрутизатор.
  4. Последовательное устройство увеличивает указатель данных.
  5. Маршрутизатор не может отправить TCP-пакет обратно на сервер.
  6. Сервер снова отправляет запрос на чтение.
  7. Последовательное устройство отвечает на маршрутизатор.
  8. Последовательное устройство увеличивает указатель данных.
  9. Маршрутизатор успешно отправляет данные обратно на сервер.

В приведенном выше сценарии вы увидите, что проблема на шаге 5 приводит к пропуску целого куска данных, поскольку последовательное устройство не имеет представления о том, чтопредыдущая операция чтения фактически не удалась.Он уже перешел к следующему фрагменту!Обычно я обнаруживаю эту проблему и использую операцию «запросить предыдущий блок данных», чтобы повторно запросить ранее пропущенный блок данных с последовательного устройства.

Вот моя проблема: я не получаю никакихисключения или ошибки из кода TCP, хотя у меня есть все, что заключено в блок try-catch SystemException, и я проверяю возвращаемое значение.

Я внимательно просмотрел свой лог-файл и заметил, что время между запросамии ответ составляет около 1 секунды, однако во время предположительно пропущенного фрагмента данных промежуток времени составлял от 2 до 3 секунд.Это предполагает, что отправка произошла, но данные не были получены, поэтому он попытался снова.Но, конечно, при повторной попытке последовательное устройство уже увеличило бы свой указатель данных до следующего набора данных.

По какой-то причине последовательное устройство получило запрос на чтение, однако данные никогда не возвращались к нему.сервер.

Я не эксперт по TCP / IP, так кто-нибудь знает, что могло случиться?Возможно ли для TCP пересылать пакеты "под капотом", не вызывая исключений и без моего ведома?

В моем коде я просто делаю что-то вроде этого:

_log.Debug(string.Format("[{0}]: Sending sync response ({1}).", 
    this._IP.ToString(), CoreUtils.PayloadToString(write_data)));

tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 
               tcpSynClBuffer.Length, SocketFlags.None);

byte function = tcpSynClBuffer[7];
byte[] data;    

if (result == 0) throw SystemException("No data received");

// ... process log buffer ...

_log.Debug(string.Format("[{0}]: Got sync response ({1}).", 
    this._IP.ToString(), CoreUtils.PayloadToString(data)));

return data;

Не было выброшено исключений, которые бы указывали на то, что что-то произошло между Send () и Receive () под капотом.,Время между двумя записями журнала отладки было вдвое больше, чем у всех остальных.Возможно или не возможно?

Ответы [ 2 ]

1 голос
/ 28 сентября 2011

Прежде всего: получение 0 байтов не означает, что вы ничего не получили. Это означает, что соединение было закрыто.

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

0 голосов
/ 06 октября 2011

Смысл TCP в том, чтобы сделать поток прозрачным для приложения.Потерянные пакеты обрабатываются TCP, а не приложением.Если TCP не получает ACK для данного пакета, он попытается повторно отправить пакет.В конечном итоге он прекратит отправку любых других пакетов и продолжит повторную отправку этого потерянного пакета, пока не получит и не истечет время подтверждения ACK или соединения.

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

Получатель примет и буферизует некоторые пакеты, пришедшие после отброшенного пакета, и "воспроизведет их", как толькопропущенный пакет получен.

...