Как лучше организовать TCP Сервер и Клиент
Модератор: Модераторы
Есть еще сетевая библиотека Lnet.
https://lnet.wordpress.com/
К тому же есть PascalScada, которую можно разширить под ваши требования. MODBUS TCP/RTU уже реализованы. Подключение к базам данных тоже через Zeos. Нехватает только MODBUS TCP сервера.
https://lnet.wordpress.com/
К тому же есть PascalScada, которую можно разширить под ваши требования. MODBUS TCP/RTU уже реализованы. Подключение к базам данных тоже через Zeos. Нехватает только MODBUS TCP сервера.
vvvch
В таком случае не заморачивайтесь ресурсами, а лучше заморочтесь вопросом удобства разработки.
Объекты, по сравнению с голыми сокетами, более "человеколюбивы". Поэтому лучше начать с какой-нибудь высокоуровневой библиотеки, типа Synapse, чтобы код был понятен с первого прочтения. Вы так быстрее добъётесь результата.
В таком случае не заморачивайтесь ресурсами, а лучше заморочтесь вопросом удобства разработки.
mig-31
PascalScada мне не понравилась, по тому и взялся писать своё. (Впрочем это частности, просто моё мнение)
А чем lnen отличается от synapse?
PascalScada мне не понравилась, по тому и взялся писать своё. (Впрочем это частности, просто моё мнение)
А чем lnen отличается от synapse?
- AlphaBlend
- постоялец
- Сообщения: 207
- Зарегистрирован: 22.05.2016 09:13:10
lnet попроще будет )
Здравствуйте! Юзаю socket юнит и не могу понять почему периодически не биндится сокет.
Код: Выделить всё
//существуем пока не мрет приложение
while (not terminated) do
begin
Fready:=false;
//'создаем сокет, слушаем, реагируем'
SockH:=fpSocket(AF_INET, SOCK_STREAM,0);
SockAddr.sin_family:=AF_INET;
SockAddr.sin_port:=htons(22409);
SockAddr.sin_addr.s_addr:=HostToNet((127 shl 24) or 1); //127.0.0.1
sizeofSockAdr:=sizeof(SockAddr);
while (fpBind(SockH,@SockAddr, sizeofSockAdr)=-1) do
begin
writeln('Ошибка связывания');
sleep(2000);
end;
writeln('Сервер запущен....');
if (fpListen(SockH,1)=-1) then
writeln('Ошибка ожидания ')
else
begin
writeln('Ожидание соединения....');
SockH:=fpaccept(SockH,@SockAddr, @sizeofSockAdr);
if SockH=-1 then
writeln('error in Accept')
else
begin
//*******************************************************
writeln('есть соединение...ok');
Fready:=true;
setlength(in_buf,512);
//получаем вход поток, пока сокет на месте (запроc не привышает 36Байт))
while (SockH<>-1) do
begin
fprecv(SockH,@in_buf[0],512,0);
if length(PChar(in_buf))=0 then break;
writeln('<<'+PChar(in_buf));
//шлем на обработку!
proc_in_query(PChar(in_buf));
in_buf[0]:=0;
end;
Fready:=false;
writeln('потеряно соединение');
writeln('Закрываю сокет! =',CloseSocket(SockH));
SockH:=-1;
sleep(2000);
end;
end;
end; //end while
end;
-
MysticCoder
- постоялец
- Сообщения: 154
- Зарегистрирован: 14.09.2013 00:20:28
Linus писал(а): почему периодически не биндится сокет.
ОС сокет с прошлого запуска не убила, бывает если сокет не закроешь перед завершением программы.
опция SO_REUSEADDR
как бы
Ладно это пол беды, как сделать так чтобы сокет при потери клиента мог принять другого? (данный мною выше код данного не выполняет, хотя это и странно)
Код: Выделить всё
CloseSocket(SockH)Ладно это пол беды, как сделать так чтобы сокет при потери клиента мог принять другого? (данный мною выше код данного не выполняет, хотя это и странно)
- serbod
- постоялец
- Сообщения: 449
- Зарегистрирован: 16.09.2016 10:03:02
- Откуда: Минск
- Контактная информация:
Рекомендую набор компонентов DataPort (также доступен через OnlinePackageManager) - это простая и удобная обертка над synapse, где есть не только TCP/UDP но и UART, FTDI, LPT. Опрос порта/сокета выполняется в отдельном потоке и не тормозит. А используя базовый абстрактный класс TDataPort в качестве свойства класса, можно подключать к объекту разные порты по выбору.
Если нужно что-то посерьезнее, то у меня есть исходники TCP/UDP сервера, рассчитанного на десятки тысяч подключений (используется lnet) с использованием очередей пакетов. И библиотеки для USB/FTDI/CAN а также для RAS (Dial-up), IP Helper (системные настройки сетевых устройств), GSM modem (AT-команды) , но они заточены под конкретное оборудование. Оттуда можно почерпнуть принципы самонастройки, самодиагностики и самовосстановления после сбоев. Как в аналоговой аппаратуре: нет контакта - не работает, есть контакт - заработало. Или может проще тут рассказать?
Если нужно что-то посерьезнее, то у меня есть исходники TCP/UDP сервера, рассчитанного на десятки тысяч подключений (используется lnet) с использованием очередей пакетов. И библиотеки для USB/FTDI/CAN а также для RAS (Dial-up), IP Helper (системные настройки сетевых устройств), GSM modem (AT-команды) , но они заточены под конкретное оборудование. Оттуда можно почерпнуть принципы самонастройки, самодиагностики и самовосстановления после сбоев. Как в аналоговой аппаратуре: нет контакта - не работает, есть контакт - заработало. Или может проще тут рассказать?
Это мне ответ?)
Нет, клиент один и только один - другое приложение. Средства только нативные. (желательно одинаковые как для c++ так и для fpc).
Задача на текущий момент сводится к тому что сервер ждет подключение, если клиент после передачи умирает - забыть про него и ждать и принять его еще раз (возможно ни один раз).
В чем пролема в коде? После смерти клиента закрываю сокет, но вот беда, он обратно не хочет прослушиваться/орендоваться и т.д.
добавил
Нет, клиент один и только один - другое приложение. Средства только нативные. (желательно одинаковые как для c++ так и для fpc).
Задача на текущий момент сводится к тому что сервер ждет подключение, если клиент после передачи умирает - забыть про него и ждать и принять его еще раз (возможно ни один раз).
В чем пролема в коде? После смерти клиента закрываю сокет, но вот беда, он обратно не хочет прослушиваться/орендоваться и т.д.
Код: Выделить всё
fpsetsockopt(SockH, SOL_SOCKET, SO_REUSEADDR, @opt, sizeof(opt) ); \0- serbod
- постоялец
- Сообщения: 449
- Зарегистрирован: 16.09.2016 10:03:02
- Откуда: Минск
- Контактная информация:
Для TCP-сервера алгоритм такой (для линукса, в винде в принципе то же самое):
1. создаем сокет, функция socket()
2. привязываем сокет к локальному IP-адресу, функция bind()
3. переводим сокет в пассивный режим приема входящих подключений, функция listen()
4. принимаем входящее подключение, функция accept(), при этом создается новый сокет, похожий на исходящий, только уже подключенный
.. пункт 4 повторяем для каждого входящего подключения
5. закрываем сокет, функция close()
Для UDP достаточно только bind(), а listen() не нужен, он не создает новых сокетов, а общается со всеми через один и тот же.
setsockopt() нужен только для извращений и тонкой настройки, в обычном порядке не нужен.
1. создаем сокет, функция socket()
2. привязываем сокет к локальному IP-адресу, функция bind()
3. переводим сокет в пассивный режим приема входящих подключений, функция listen()
4. принимаем входящее подключение, функция accept(), при этом создается новый сокет, похожий на исходящий, только уже подключенный
.. пункт 4 повторяем для каждого входящего подключения
5. закрываем сокет, функция close()
Для UDP достаточно только bind(), а listen() не нужен, он не создает новых сокетов, а общается со всеми через один и тот же.
setsockopt() нужен только для извращений и тонкой настройки, в обычном порядке не нужен.
serbod писал(а):Для TCP-сервера алгоритм такой (для линукса, в винде в принципе то же самое):
4. принимаем входящее подключение, функция accept(), при этом создается новый сокет, похожий на исходящий, только уже подключенный
.. пункт 4 повторяем для каждого входящего подключения
Вот какую забыл важную мелочь, создается новый сокет "клиента"...
Код: Выделить всё
procedure ServerSockThread.Execute;
var
SockAddr:TInetSockAddr;
sizeofSockAdr:longint;
opt:integer;
in_buf:TSockBuf;
begin
//существуем пока не мрет приложение
Fready:=false;
//'создаем сокет, слушаем, реагируем'
SockH:=fpSocket(AF_INET, SOCK_STREAM,0);
opt:=1;
fpsetsockopt(SockH, SOL_SOCKET, SO_REUSEADDR, @opt, sizeof(opt) );
SockAddr.sin_family:=AF_INET;
SockAddr.sin_port:=htons(22409);
SockAddr.sin_addr.s_addr:=HostToNet((127 shl 24) or 1); //127.0.0.1
sizeofSockAdr:=sizeof(SockAddr);
while (fpBind(SockH,@SockAddr, sizeofSockAdr)=-1) do
begin
writeln('Ошибка связывания');
sleep(2000);
end;
writeln('Сервер запущен....');
if (fpListen(SockH,1)=-1) then
writeln('Ошибка ожидания ')
else
begin
writeln('Ожидание соединения....');
while (not terminated) do
begin
Client:=fpaccept(SockH,@SockAddr, @sizeofSockAdr);
if Client=-1 then
writeln('error in Accept')
else
begin
//*******************************************************
writeln('есть соединение...ok');
Fready:=true;
setlength(in_buf,36);
//получаем вход поток, пока сокет на месте (запроc не привышает 36Байт))
while (Client<>-1) do
begin
fprecv(Client,@in_buf[0],35,0);
if length(PChar(in_buf))=0 then break;
writeln('<<'+PChar(in_buf));
//шлем на обработку!
proc_in_query(PChar(in_buf));
fillchar(in_buf[0],36,0);
end;
Fready:=false;
writeln('потеряно соединение');
writeln('Закрываю сокет! =',CloseSocket(Client));
end;
end; //end while
end;
end;Все работает (для указанных выше задач).
Про MODBUS кстати делал так:
1) ставим драйвера MBX7 (у него можно настроить разные типы подключения)
2) ходим через интерфейс этого драйвера
1) ставим драйвера MBX7 (у него можно настроить разные типы подключения)
2) ходим через интерфейс этого драйвера
полная реализация протокола MODBUS есть в различных компонентах. Он не сложен.
Дополняю тему вопросом: как установить таймаут на чтение из сокета? (fprecv)
а так же проверить сколько скопилось в буфере отправки.
а так же проверить сколько скопилось в буфере отправки.
