PDA

Просмотр полной версии : PLC 110-30 v2 & tcp ip



lazy
21.01.2019, 10:28
Добрый день!

Плк 110-220.30.К-М (м2) прошивка 0.3.76. MinCycleLength = 0(ms), в реальности, что то около 2ms.
Задача, передавать данные по Ethernet как можно чаще, пакет около 70 байт (тестовый) планируется длиннее, но пока в нем всякие счетчики, счетчик отправленных пакетов, циклов ПЛК в котором идет передача, время итд... Отправка пакета происходит в каждом втором цикле ПЛК в среднем каждые 4мс.

1. Открываем сокет: SysSockCreate( SOCKET_AF_INET, SOCKET_STREAM, SOCKET_IPPROTO_IP );
2. Настраиваем: SysSockSetOption( m_aSockets[0], SOCKET_SOL, SOCK_NBIO, 0, 0 );
3. Связываем:
o_aSAddress[0].sin_family := SOCKET_AF_INET;
o_aSAddress[0].sin_addr := SOCKET_INADDR_ANY;
o_aSAddress[0].sin_port := SysSockHtons( i_pOptions^.wPort );
SysSockBind( m_aSockets[0], ADR( o_aSAddress[0] ), SIZEOF( o_aSAddress[0] ) );
4. Ждем коннекта SysSockListen... и коннектимся SysSockAccept все ок;
5. Далее читаем SysSockRecv( m_aSockets[o_yCNow], i_pData, i_dnSize, 0 ), так как ничего не приходит переходим к передаче:
SysSockSend( m_aSockets[o_yCNow], i_pData, i_dnSize, 0 ); Вообще передача выглядит так:

(* при входе o_dnRes = 0 *)
IF i_pDevice^.eIO = IO_S_REPLY THEN
i_pSocket^.Write( i_pData := ADR( m_aBuffer[o_dnRes] ), i_dnSize := m_dnBufferCnt - o_dnRes, i_pExpect := i_pExpect );
IF i_pSocket^.o_dnRes < 0 THEN (*здесь o_dnRes<0 только при срабатывании "таймаута"(500мс) иначе 0 или переданные байты*)
i_pDevice^.yError := MB_TIME_OUT_ERROR;
i_pDevice^.eIO := IO_S_LISTEN;
o_bDone := TRUE;
o_dnRes := 0;
ELSE
o_dnRes := o_dnRes + i_pSocket^.o_dnRes;
IF o_dnRes = m_dnBufferCnt THEN
i_pDevice^.eIO := IO_S_LISTEN;
o_bDone := TRUE;
o_dnRes := 0;
END_IF
END_IF
END_IF

Все передается в один вызов SysSockSend.
Так вот, в течении 10 сек такой работы пакеты приходят не по порядку. то есть отправляли, например, 1й 2й 3й 4й, а приходят 1й 4й 2й 3й. Если передавать с задержкой хотя бы 20мс все приходит как положено. Есть подозрение, что данные в буфере SysSockSend перетираются.
Прикладываю текстовый файл на стороне приема начинается с пакета 99758.

Scream
21.01.2019, 11:41
Насколько помню tcp\ip не гарантирует ни длину соблюдать ни очередность, главное доставить, а как - дело второе.

lazy
21.01.2019, 11:54
как то так: Транспортный уровень стека TCP/IP (уровень 3) обеспечивает передачу данных между прикладными процессами. Транспортный уровень включает два протокола TCP и UDP. Протокол управления передачей TCP (Transmission Control Protocol) является надёжным протоколом с установлением соединения, позволяющим управлять потоком, т.е. без ошибок доставлять байтовый поток с одной машины на любую другую машину составной сети. Для того чтобы обеспечить надёжную доставку данных, протокол TCP предусматривает установление логического соединения. Это позволяет ему нумеровать пакеты, подтверждать их прием квитанциями, в случае потери организовывать повторные передачи, распознавать и уничтожать дубликаты, доставлять прикладному уровню в том порядке, в котором они были отправлены.

Scream
21.01.2019, 14:03
Ну тогда вот)
1.2.2 TCP Если IP-пакеты содержат инкапсулированные пакеты TCP, программы IP передадут их вверх уровню TCP. TCP последовательно нумерует все пакеты и выполняет исправление ошибок, и реализует таким образом виртуальные соединения между хостами. Пакеты TCP содержат последовательные номера и подтверждения о приеме пакетов, поэтому пакеты, принятые не в порядке передачи, могут быть переупорядочены , а испорченные пакеты повторно посланы.

Scream
21.01.2019, 14:09
Нет, вообще я всегда думал что обязаны придти хотябы в том порядке что были отправлены, иначе всё усложняется в разы, то что дробиться могут как угодно это понятно. Но где-то тоже сталкивался с такой проблемой через 3g сеть. Часто было что они слипались по 2-3 штуки и бывало id 4 приходил раньше id 3 (сам помечал).

lazy
21.01.2019, 14:19
и что значит эта фраза (#5)? ровно вот что:

TCP делит информацию, которую надо переслать, на несколько частей и нумерует каждую часть, чтобы позже восстановить порядок. Чтобы пересылать эту нумерацию вместе с данными, он обкладывает каждый кусочек информации своей обложкой — TCP-конвертом, который содержит соответствующую информацию.
Получатель по получении распаковывает IP-конверты и видит TCP-конверты, распаковывает и их и помещает данные в последовательность частей в соответствующее место. Если чего-то недостает, он требует переслать этот кусочек снова. В конце концов, информация собирается в нужном порядке и полностью восстанавливается. )

(#6)да, пакеты могут приходить склеенными (или разорванными), но порядок не отменяецо )

lazy
21.01.2019, 17:07
ок. правильно SOCKET_IPPROTO_TCP? щя попробую )

capzap
21.01.2019, 17:15
была ведь уже тема, где с помощью wireshark искали проблемы в М02

lazy
21.01.2019, 18:14
SOCKET_IPPROTO_TCP не помогает по ходу (

lazy
22.01.2019, 13:50
У меня с modbus tcp тоже проблем нет, правда обмен 15-30 мс. А вот тут, все что с задержкой меньше 40 мс... пакеты начинают приходить в разнобой.
Вроде делал по образу и подобию... Я проект выложу, может не лень кому глянуть будет. В действии Default нужно менять r_ServerOpt.tTimeOut - сейчас 40ms;
Получать пакеты и сохранять в файл можно программой Terminal.

Валенок
23.01.2019, 19:47
...............

lazy
24.01.2019, 10:19
ну кагбэ да, но есть нюанс )
работа модбас сервера начинается с запроса, то есть чтения сокета. и у меня с чтения, только ничего не приходит. казалось бы и что? так вот. добавил перед записью в сокет SysSockSelect:

IF m_aSockets[o_yCNow] <> SOCKET_INVALID THEN
m_tv.tv_sec := 0;
m_tv.tv_usec := 0;
m_fds.fd_count := 1;
m_fds.fd_array[0] := m_aSockets[o_yCNow];
IF SysSockSelect( SOCKET_FD_SETSIZE, 0, ADR( m_fds ), 0, ADR( m_tv ) ) > 0 THEN
o_dnRes := SysSockSend( m_aSockets[o_yCNow], i_pData, i_dnSize, 0 );
END_IF
ELSE
o_dnRes := SOCKET_INVALID;
END_IF

и что происходит. модбас работает, а вызов того же FB но при условии что при чтении сокета там ничего не было приводит к перезагрузке ПЛК по вочдогу. один и тот же код.
1. читаем сокет -> что то пришло -> пишем с вызовом SysSockSelect - все ок.
2. читаем сокет -> ничего не приходило -> пишем с вызовом SysSockSelect - перезагрузка по вочдог.

так же к перезагрузке по вочдог приводит вызов SysSockSelect перед SysSockRecv и перед SysSockAccept.

Валенок
25.01.2019, 08:48
..............

lazy
25.01.2019, 14:52
Работа сервера начинается с проверки на желающих подключился.

ну пусть так. все подключились сервер то молчит ) ему нужен запрос чтобы ответить. а ты попробуй при подключении просто гнать клиенту пакеты один за одним. и посмотри что будет. селект я тоже не использую. просто копаю во все стороны. пока селект показал что бибка ведет себя по разному с запросоми и без. вот что хотел сказать про селект. кста лучше делать m_tv.tv_usec := 1; тогда перед чтением не падает система, но возвращает она какую то хрень. сегодня некогда разбирацо с понедельника начну )

lazy
29.01.2019, 15:43
Беру свои слова обратно, все работает как надо. Дело было в самом терминале. Нашел в интернетах другой (кста третий на двух были проблемы), кому интересно вот сцыль на него: https://www.hw-group.com/software/hercules-setup-utility. Пакеты отправляются в каждом цикле ничего не теряется и приходят по порядку )

PS: SysSockSelect перезагружает ПЛК по вочдогу, не используйте.