PDA

Просмотр полной версии : TCP клиент на SysLibSockets



Carter
18.09.2015, 09:52
Добрый день. Тестирую пример TCP клиента на вышеуказанной библиотеке на ПЛК154. Интересует следующее: когда открываю соединение и клиент подключается к серверу и держит соединение несколько секунд, после соединение закрывается, если ничего не отправлять на сервер или обратно. Как держать соединение пока сервер работает и как ловить ошибки отправки по сокету в Codesys?

Филоненко Владислав
18.09.2015, 13:11
Это стандартное поведение сокета. если нет данных - через таймаут сокет закрывается.
Есть функция получения кода последней ошибки.

Carter
18.09.2015, 13:20
Функция SysSockSetOption(socket, SOCKET_IPPROTO_TCP, SOCKET_TCP_NODELAY, ADR(sa), SIZEOF(sa)); меняет таймаут?

Сформулирую вопрос иначе: могу ли я открыть соединение и, к примеру, один раз в 20 секунд что-то отправлять с клиента не разрывая соединение?

Филоненко Владислав
19.09.2015, 13:50
Стек IP в 1хх достаточно сильно урезан и опции сокетов не поддерживаются.

Carter
21.09.2015, 10:09
Значит стандартными средствами я не смогу организовать свой протокол обмена? Если какие-то пути решения задачи? Кто-нибудь сталкивался с этим?

_Pavel_
21.09.2015, 10:18
Добрый день. Тестирую пример TCP клиента на вышеуказанной библиотеке на ПЛК154. Интересует следующее: когда открываю соединение и клиент подключается к серверу и держит соединение несколько секунд, после соединение закрывается, если ничего не отправлять на сервер или обратно. Как держать соединение пока сервер работает и как ловить ошибки отправки по сокету в Codesys?

Мы используем пакеты "Heartbeat" раз в секунду для контроля и поддержания соединения во время отсутствия активного обмена. Функция SysSockSend возвращает количество успешно переданных байт => можно ловить ошибки отправки.

Carter
21.09.2015, 10:31
Мы используем пакеты "Heartbeat" раз в секунду для контроля и поддержания соединения во время отсутствия активного обмена. Функция SysSockSend возвращает количество успешно переданных байт => можно ловить ошибки отправки.
Идея Ваша решает эту проблему и, видимо, без "пинговых" пакетов мне не обойтись. Попробую ловить ошибки отправки как Вы сказали.
И очень смущает, что SysSockConnect() не возвращает TRUE, хотя работает...

Yegor
21.09.2015, 11:43
И очень смущает, что SysSockConnect() не возвращает TRUE, хотя работает...У Овна в ПЛК 1хх что в SysLibSockets, что в SysLibCom бардак в аргументах и возвращаемых значениях.

Carter
22.09.2015, 14:11
Подскажите еще момент, передаю строку командой SysSockSend(), на серверу получаю строку с "мусором" , аналогично с сервера приходят данные с ненужными символами.

Филоненко Владислав
22.09.2015, 16:50
размер точно указываете или как strlen()?

Carter
22.09.2015, 17:12
Указываю как SIZEOF(mystring).

Филоненко Владислав
22.09.2015, 18:22
вот вот, а в строке данных меньше чем её размер. Надо явно указывать сколько байт посылать.

Scream
22.09.2015, 20:25
KeepAlive называется чтобы сокет не умирал. Я в этих пакетах заодно данные передаю.

Carter
23.09.2015, 09:27
вот вот, а в строке данных меньше чем её размер. Надо явно указывать сколько байт посылать.
Исправил, помогло, спасибо за подсказку.

Carter
29.09.2015, 16:46
Подскажите момент: одновременно по таймеру выполняю две функции SysSockSend(), сокет создан в неблокирующем режиме SysSockIoctl(socket, SOCKET_FIONBIO, 1), но результат выполнения второй функции возвращает -1. Сделал это ради эксперимента, так как возможна одновременная отправка данных по сокету, а успех отправки очень важен.

Филоненко Владислав
30.09.2015, 10:46
А вставить паузу?

Carter
30.09.2015, 11:00
Я рассматриваю вариант если совпадет отправка двух или более пакетов данных по сокету, то я не смогу избежать потери информации. Или неблокирующие сокеты не поддерживаются?

_Pavel_
30.09.2015, 22:43
Я рассматриваю вариант если совпадет отправка двух или более пакетов данных по сокету, то я не смогу избежать потери информации. Или неблокирующие сокеты не поддерживаются?

Если я правильно Вас понял, Вы пытаетесь вызвать дважды и более функцию SysSockSend за один цикл ПЛК. Я так не пробовал, но у меня, сформированные в течении цикла ПЛК пакеты складываются в специальный буфер-накопитель. Затем, в конце цикла я формирую буфер данных для отправки по сети в виде "склейки" пакетов из буфера-накопителя и передаю его с помощью SysSockSend, далее, убедившись, что весь буфер передан корректно (здесь я учитываю, что на это может уйти не один цикл ПЛК) , приступаю к формированию и передаче следующей склейки. Процесс накопления буфера сообщений (события объекта) и процесс передачи этих сообщений в сеть происходят асинхронно. Это конечно для Stream-сокета.

Carter
01.10.2015, 12:06
Если я правильно Вас понял, Вы пытаетесь вызвать дважды и более функцию SysSockSend за один цикл ПЛК.
Да, вы правильно поняли. С сокетами раньше работал, но не в кодесис, вызывал функции отправки последовательно, видимо была задержка и все отправлялось, отправки склеивались. Создал, как Вы сказали, "буфер", приходится складывать в него байтовые массивы, по другому решения задачи не вижу. Да и интервал выполнения установил 100мс, реже сокет не справляется с отправкой...

Scream
01.10.2015, 12:48
Да, вы правильно поняли. С сокетами раньше работал, но не в кодесис, вызывал функции отправки последовательно, видимо была задержка и все отправлялось, отправки склеивались. Создал, как Вы сказали, "буфер", приходится складывать в него байтовые массивы, по другому решения задачи не вижу. Да и интервал выполнения установил 100мс, реже сокет не справляется с отправкой...

наверное чаще?

Carter
01.10.2015, 13:00
наверное чаще?
Да, перепутал, не чаще. Надеюсь, что на правильном пути.

Валенок
01.10.2015, 19:10
Да отправляется чаще .Просто не получилось

Carter
02.10.2015, 09:56
Да отправляется чаще .Просто не получилось
Что не получилось? Отправить не получилось? Или что имеете ввиду? Если есть что подсказать, то подскажите явно, а не воду пишите, уже несколько дней одно и тоже.

Carter
08.10.2015, 10:06
Друзья, может подскажете, как вы справлялись с сокетами, если, конечно, это для вас не секретная информация. Какое время цикла ставите, чтение\запись делаете в одном цикле, после каждой транзакции закрываете сокеты или это зависит от ПЛК? На ПЛК154 получается читать и писать в одном цикле, если SysSockCreate() возвращает 2, если 1, то читает сокет через раз, как будто сокет создался в блокирующем режиме, хотя это не так.

_Pavel_
08.10.2015, 14:30
Какое время цикла ставите

У меня на ПЛК 110 new и ПЛК 100 МинВЦ = 0 и прекрасно и максимально быстро работает.


чтение\запись делаете в одном цикле,

В разных.


транзакции закрываете сокеты или это зависит от ПЛК?

При работе с HTTP закрываю сокет после каждой транзакции. С собственным протоколом работаю при постоянно открытом соединении.


На ПЛК154 получается читать и писать в одном цикле, если SysSockCreate() возвращает 2, если 1, то читает сокет через раз, как будто сокет создался в блокирующем режиме, хотя это не так.

Я думаю что не стоит писать и читать в одном цикле. По сокетам есть очень полезное видео (http://www.youtube.com/watch?v=ThVLXygHnnU), правда для CDS V3, но суть одна.

lazy
08.10.2015, 14:39
Сокеты не закрываю, точнее, закрываю если сокет "сервер" и к нему нет обращений какое то время (так определяю обрыв связи) чтобы в следующем цикле открыть снова. Клиенты бомбят без остановки но за цикл либо пишу либо читаю, причем если сокетов открыто много то читаю/пишу только одним сокетом, на следующем цикле другим итд. Если прием/передача проходят с ошибкой клиента закрываю чтобы открыть в следующем цикле.
С серверами сложнее. В одном цикле перебираю все фунцией чтения, если с какого есть данные(запрос) - перебор прекращаю на следующем цикле если нужно ответить отвечаю и(или) продолжаю перебор оставшихся сокетов. И так по кругу.
вощемто работает )

Carter
08.10.2015, 15:06
Спасибо за ответы! Разделил чтение\отправку, чередую в цикле. Проблема только в том, что не всегда могу получить данные, повторюсь, если если SysSockCreate() возвращает 1, если 2, то сколько бы я с сервера ни отправлял, все доходит...

lazy
08.10.2015, 15:35
Есть у меня подозрение... )
Насчет дискрипторов... У меня сокеты открываюцо с дискрипторами 1,2,3...15. Первый всегда создается с дискриптором 1. (если у вас первый с двойкой смотрите код внимательнее возможно их открываецо два и отсюда все траблы)

открываем:
IF m_dnSocket = SOCKET_INVALID THEN
m_dnSocket := SysSockCreate( ... );
END_IF

А вот с закрытием сложнее...

o_dnRes := BOOL_TO_INT( SysSockClose ( m_dnSocket ) );

для 110-го:
IF o_dnRes = 0 THEN
m_dnSocket := SOCKET_INVALID;
END_IF
причем в какой-то прошивке SysSockClose возвращал правильное значение но реально сокет не закрывался. (значит следующий отрывался с дискриптором на еденичку больше)

для 100-го:
IF o_dnRes = 1 THEN
m_dnSocket := SOCKET_INVALID;
END_IF

по моему как то так. кто сможет опровергните )

Carter
08.10.2015, 16:41
У меня открывается или с дескриптором 1 или 2, других пока не наблюдал, проверю вариант с незакрытием сокета. Просто, по логике вещей, если у меня открыто два сокета, то траблов как раз таки нет...

Филоненко Владислав
09.10.2015, 08:38
Итак, при запуске должен открываться сокет с handle=1, 0-й занят средой CoDeSys.
Если при открытии 1 сокета handle=2 - что-то тут не так.

Учтите, что listen->accept позвращает тот-же handle, т.е. как в винде нельзя поступать - открыть сокет, поставить в listen и плодить сокеты по приходящим соединениям.
1 сокет - 1 и только 1 соединение.

Scream
09.10.2015, 09:28
Итак, при запуске должен открываться сокет с handle=1, 0-й занят средой CoDeSys.
Если при открытии 1 сокета handle=2 - что-то тут не так.

Учтите, что listen->accept позвращает тот-же handle, т.е. как в винде нельзя поступать - открыть сокет, поставить в listen и плодить сокеты по приходящим соединениям.
1 сокет - 1 и только 1 соединение.

Насколько я помню, вроде плк 160, открывает с 11 дескриптора и до 16. Как тут тогда быть?

Carter
09.10.2015, 10:21
Беда, конечно, что каждый ПЛК ведет себя по-разному, а под рукой нет другого, чтобы проверить...

capzap
09.10.2015, 10:51
Беда, конечно, что каждый ПЛК ведет себя по-разному, а под рукой нет другого, чтобы проверить...

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

Carter
09.10.2015, 11:11
это от программиста тоже зависит
Замечание ваше справедливо, себя не оправдываю, действительно мало опыта. Цель всех моих вопрос понять, где мои ошибки, а где поведение ПЛК.
Почему сокет открывается со 2-го десткриптора разобрался, но вот почему сокет читается "через раз" с дескриптором 1 так и не понял.

Филоненко Владислав
09.10.2015, 13:56
Программу то приведите, чего мы тут гадаем. На ПЛК100 мы даже WEB-сервер делали многопользовательский с визуализацией и графиками. Так что сокеты рабочие, но есть нюансы.

Carter
09.10.2015, 14:51
Программу то приведите, чего мы тут гадаем. На ПЛК100 мы даже WEB-сервер делали многопользовательский с визуализацией и графиками. Так что сокеты рабочие, но есть нюансы.
Вот, собственно, ФБ и пару функций, которыми пользуюсь, ФБ многим знаком, из оскатовской библиотеки.
20344

lazy
09.10.2015, 15:51
Эммм... что то у вас с переходом из step:=0;в step:=1; зачем прыгать туда-сюда из цикла в цикл? Принимайте (то есть будте в step:=1) пока не примите или не выйдет таймаут. Ну и с передачей собственно так же )

Carter
09.10.2015, 16:11
Эммм... что то у вас с переходом из step:=0;в step:=1; зачем прыгать туда-сюда из цикла в цикл? Принимайте (то есть будте в step:=1) пока не примите или не выйдет таймаут. Ну и с передачей собственно так же )
Суть в том, что не всегда получается прочитать то, что отправил с сервера. Пробовал оставить в цикле только чтение, результат тот же.

lazy
09.10.2015, 16:46
и все таки: передаем - передали? да - принимаем - приняли? да - передаем. инициатором обмена должен быть клиент. сервак "слушает и отвечает" (это я к тому что "оставил в цикле только чтение" )
попробуйте вместо TcpReceiveData result:= SysSockRecv( diSocket, ADR(byBuffer[0]), 100,0);
у вас "сервак" шлет данные с какой периодичностью? может сервак передает а сокет закрылся по ready и(или) errcheck?

Carter
09.10.2015, 16:59
у вас "сервак" шлет данные с какой периодичностью? может сервак передает а сокет закрылся по ready и(или) errcheck?
Сервер не отвечает на посылки, пока такой алгоритм, НО я могу с сервера в произвольный момент времени отправить данные, на которые должен отреагировать клиент, если они не доходят с первого раза, то придется "долбить" клиента, чего не совсем хочется.

И еще, пока я буду ждать от сервера ответа(который может и не придти), как в нынешней ситуации, то у меня сокет по таймауту закрывается, безысходность какая-то...

lazy
09.10.2015, 17:10
ну дык вот )
у вас сокет принимает 5 секунд и закрываецо. а вы шлете ) оставьте только прием. уберите ready и errcheck и проверьте )

Carter
09.10.2015, 17:17
В том примере, что я отправил, пусть он не совсем правильный, по идее-то, прием должен работать. Закрываться сокет стал, когда сделал по вашему совету, отправил и читаю)) я не шлю с сервера когда клиент отключен.

lazy
09.10.2015, 17:32
уберать ready и errcheck нужно не насовсем а временно чтобы проверить )

Филоненко Владислав
11.10.2015, 13:04
Вот пример сервера. Делайте по аналогии.

Carter
12.10.2015, 10:57
Вот пример сервера. Делайте по аналогии.
Собственно, ФБ, которым пользуюсь, не хуже, хотя речь идет о клиенте. В Вашем примере в одном цикле и запись, и чтение, или я ошибаюсь?

Филоненко Владислав
12.10.2015, 16:09
Хуже, лучше. Главное- хвост! (т.е. работает)