CODESYS форум

Добро пожаловать на официальный форум CODESYS, 3S-Smart Software Solutions GmbH | A member of the CODESYS Group
Deutsche Version English version russian version 
Текущее время: Сб авг 24, 2019 8:47 am

Часовой пояс: UTC+01:00




Начать новую тему  Ответить на тему  [ 13 сообщений ] 
Автор Сообщение
 Заголовок сообщения: TCP-клиент на контроллере
СообщениеДобавлено: Ср фев 10, 2010 5:38 am 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Имеется контроллер на основе Beck SC13.
Делаю TCP-клиент для рассылки данных раз в одну секунду допустим.
Все работает нормально, но как только я из сервера вытаскиваю сетевой кабель (т.е. теряется связь), контроллер то ли зависает, то ли очень медленно работает. В итоге связь с контроллером теряется из CDS, если вставить кабель назад, то через некоторое время связь восстанавливается.
Как я понял дело в SysSockConnect, если он не может соединиться то все выше перечисленное творится, а по идее он же должен возвращать FALSE, но этого не делает.
Код:
sa.sin_family:=SOCKET_AF_INET; 
sa.sin_addr:=SysSockInetAddr('192.168.1.15');
sa.sin_port:=SysSockHtons(502);

      tmr(IN:=start_TON,PT:=t#1s);                  (*межпосылочный таймер*)
      tmrS(IN:=tmr.Q,PT:=t#500ms);            (*пауза между соединением и посылкой*)
      IF NOT start_TON THEN
         start_TON:=TRUE;                     (*запуск таймера 1*)
      END_IF
      IF tmr.Q THEN
         bSent:=TRUE;                           (*на выходе таймера 1 разрешение посылки, сброс таймера*)
         start_TON:=FALSE;
      END_IF

IF bSent THEN                                 (*посылка*)
CASE stat OF
0:
stat:=1;
1:
dSocket:=SysSockCreate(SOCKET_AF_INET, SOCKET_STREAM,0);         (*создание TCP-сокета*)
stat:=2;

2:
(*соединение*)
IF SysSockConnect(dSocket, ADR(sa), SIZEOF(sa)) THEN
stat:=4;
ELSE
stat:=5;
END_IF

4:
IF NOT tmrS.Q AND dSocket >0 THEN                                 (*после паузы после соединения*)
stSend:=SysSockSend(dSocket, ADR(bufS), SIZEOF(bufS), 0);               (*посылка сообщения*)
stat:=5;
END_IF

5:
stClose:=SysSockClose(dSocket);                                    (*закрытие сокета*)
dSocket:=-1;                                                      (*нет сокета*)
stat:=1;                                                         (*сброс последовательности соединения*)
bSent:=FALSE;                                                   (*посылка завершена*)
END_CASE
END_IF


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 8:04 am 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
Используйте неблокирующие сокеты
Код:
VAR
  diSocket:DINT:=SOCKET_INVALID;
  diParam:DINT:=1;
END_VAR

SysSockIoctl( diSocket, SOCKET_FIONBIO, ADR(diParam));


Что используется в качестве TCP-сервера?


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 8:55 am 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Спасибо за ответ!
Я их так и использовал, но так как этот чип медленоват, я не получал адекватно результата и подумал, что решение не в этом. Сейчас сделал перед переводом в неблокирующий, перед коннектом и перед отправкой паузы, что решило проблему.
Теперь не понятно, что возвращают функции SysSockIoctl и SysSockConnect, они у меня в нуле всегда, иногда коннект возвращает TRUE.
В качестве сервера используется Modbus TCP/RTU шлюз, я в итоге записываю с ПЛК на другой контроллер (MB RTU) переменную.
Код:

      tmr(IN:=start_TON,PT:=t#1s);                  (*межпосылочный таймер*)
      tmrIO(IN:=tmr.Q,PT:=t#100ms);
      tmrC(IN:=tmr.Q,PT:=t#200ms);
      tmrS(IN:=tmr.Q,PT:=t#300ms);            (*пауза между соединением и посылкой*)
      IF NOT start_TON THEN
         start_TON:=TRUE;                     (*запуск таймера 1*)
      END_IF
      IF tmr.Q THEN
         bSent:=TRUE;                           (*на выходе таймера 1 разрешение посылки, сброс таймера и увеличение счетчика*)
         start_TON:=FALSE;
      END_IF

IF bSent THEN                                 (*посылка*)
CASE stat OF
0:
dSocket:=SysSockCreate(SOCKET_AF_INET, SOCKET_STREAM,0);         (*создание TCP-сокета*)
stat:=1;

1:
IF NOT tmrIO.Q AND dSocket >0 THEN
stIOSock:=SysSockIoctl(dSocket, SOCKET_FIONBIO, ADR(dParam));
stat:=2;
END_IF

2:
IF NOT tmrC.Q AND dSocket >0 THEN
stConn:=SysSockConnect(dSocket, ADR(sa), SIZEOF(sa));               (*соединение*)
stat:=4;
END_IF

4:
IF NOT tmrS.Q AND dSocket >0 THEN                                 (*после паузы после соединения*)
stSend:=SysSockSend(dSocket, ADR(bufS), SIZEOF(bufS), 0);               (*посылка сообщения*)
stat:=5;
END_IF

5:
stClose:=SysSockClose(dSocket);                                    (*закрытие сокета*)
dSocket:=-1;                                                      (*нет сокета*)
stat:=0;                                                         (*сброс последовательности соединения*)
bSent:=FALSE;                                                   (*посылка завершена*)
END_CASE
END_IF


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 9:50 am 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
Была похожая проблема: в качестве TCP-сервера был преобразователь MOXA NPort 5110, при потере связи (дернули кабель) в контроллере сокет закрывался, а мохе нет. В итоге последующий коннект был невозможен, пока сокет в мохе не будет закрыт.
На стороне TCP-сервера необходимо включить включить режим TCP Alive Check (периодическая отправка пакетов для проверки связи) и настроить таймаут TCP Alive Check Timeout, по истечении которого сервер должен закрыть сокет и перейти в режим ожидания соединения (listen).
Фунция SysSockIoctl должна возвращать отличный от 0 результат типа DINT. Функция SysSockConnect должна возвращать TRUE в случае успеха.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 10:56 am 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Да, в NPort такие настройки есть, но у меня MGate тоже Моха, в нем настроек нет по ТСР, но он я как заметил при разрыве сокет закрывает, так что с ним проблем нет.
Сейчас все в принципе работает и с кабелем и без кабеля, т.е. контроллер не виснет и отправка идет как положено.
Но смущает что SysSockIoctl всегда в нуле, а SysSockConnect иногда возвращает TRUE, причем хаотично - может две посылки подряд быть 1, может и через посылок 40.
И еще, да SysSockConnect возвращал TRUE, но до того как начал использовать SysSockIoctl.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 11:44 am 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
Попробуйте вынести таймер подключения непосредственно в шаг 2
Код:
   STATE_CONNECT:
      oTON(IN:=TRUE , PT:=tmConnectTimeout);
      xConnectRez:=SysSockConnect(diSocket,ADR(sa),SIZEOF(sa));

      IF xConnectRez THEN
         (*есть коннект*)
         
      ELSE
         (*проверяем таймер*)
         IF oTON.Q THEN
            (*таймаут истек, выходим с ошибкой*)
            bState:=STATE_CLOSE;
         END_IF
      END_IF


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 12:31 pm 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Дело не в мохе, потому как у нее 16 клиентов может быть и я пробовал вырубать ее, чтобы сбросить подключения.
Вставил, как вы посоветовали таймер, вроде работает.
По всей видимости, моха просто не успевала ответить accept, а я данные уже посылал, данные все через нее нормально проходили, только ПЛК не знал что все-таки соединен.
Сейчас попробую поиграться с таймаутами.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 12:52 pm 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
Чтобы локализовать проблему, надо на обеих сторонах контролировать состояние сокета: на плк я запускаю команду netstat, для мохи можно использовать NPort Administrator (не знаю, есть ли аналог для MGate). Прогнать 1 цикл программы и проследить весь жизенный цикл сокета на клиенте и сервере...

PS. Вместо NPort Administrator также можно использовать web-интерфейс или telnet.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср фев 10, 2010 1:18 pm 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Так вот именно, у этой железки нет такого функционала как у NPort. Есть монитор в MGate Manager, но он только по передаче/приему, по соединенным устройствам нет информации.
Теперь понял, таймеры немного не правильно использовал, в итоге не дождавшись коннекта, я отправлял данные.
Все, вроде разобрался. Спасибо!


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пт фев 12, 2010 11:06 am 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
В итоге сделал так:
1. создал сокет
2. перевел в неблокирующий режим
3. соединение с таймаутом
4. после удачного соединения выдерживается еще таймаут и передаются данные
5. закрыл сокет
Кстати, SysSockConnect действительно возвращает TRUE при удачном соединении, иначе False, а вот SysSockIoctl возвращает -1 при неудаче, отличное от -1 (у меня всегда 0) при удаче.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пт фев 12, 2010 1:32 pm 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
В справке по библиотеке SysLibSockets написано, что вызовы функций транслируются в системные вызовы ОС контроллера. Т.е. вызов SysSockIoctl будет обработан как вызов ioctl. В моем случае, ОС в ПЛК - linux, вызов ioctl возвращает -1 при ошибках, 0 или положительное число в случае успеха. В коде программы стоит следующая проверка
Код:
IF SysSockIoctl(diSocket, SOCKET_FIONBIO, ADR(diParam))<>0 THEN

и она работала :)
Надо будет поправить условие на >=0
Кстати, зачем каждый раз закрывать сокет и затем вновь создавать его?


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пн фев 15, 2010 4:49 am 
Не в сети

Зарегистрирован: Ср ноя 11, 2009 3:31 pm
Сообщения: 14
Я сделал проверку <> -1 - работает.
Где-то читал, что сокет лучше закрывать если пауза больше секунды, у меня будет запись раз в 5-10 секунд.
В итоге сделал ФБ модбас-функции 06, который все это выполняет, у него на входе Модбас адрес, регистр и данные, на выходе статус: 0 - работает или не запускался пока, -1 - ошибка, 1 - успех. Вот только необходимо постоянно вызывать ФБ, чтобы он внутри все действия выполнили и вернул статус (типа как SysSockConnect), правильно ли так?


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пн фев 15, 2010 5:00 am 
Не в сети

Зарегистрирован: Ср июн 20, 2007 12:10 pm
Сообщения: 31
Aleksey Pshikov писал(а):
Вот только необходимо постоянно вызывать ФБ, чтобы он внутри все действия выполнили и вернул статус (типа как SysSockConnect), правильно ли так?

Все верно! Программа работает циклически и постоянно будет вызывать экземпляр ФБ.


Вернуться к началу
Показать сообщения за:  Поле сортировки  
Начать новую тему  Ответить на тему  [ 13 сообщений ] 

Часовой пояс: UTC+01:00


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB