#

Как передать информацию по сети (UDP сокеты в Lazarus)

Для передачи информации от одной программы к другой можно применить один из сетевых протоколов, таких как UDP. Он позволяет быстро обмениваться любыми данными между двумя или несколькими работающими параллельно программами, причем как на одном ПК, так и на других компьютерах в сети.
Причем не важно на каком языке программирования эти программы будут работать, данный сетевой интерфейс сможет их объединить.
Для реализации такой связи в данной статье будет показано применение технологии сетевых UDP сокетов на базе среды разработки Lazarus IDE на языке free pascal.
К сожалению, в сети на данный момент информация о данном типе соединения отрывочная, или слишком усложненная. Это не дает разобраться с базовыми моментами организации такой технологии. Поэтому здесь показана минимально необходимые действия для осуществления передачи информации по сети по протоколу UDP.

Библиотека Synapse

Организацией различного рода связей занимается библиотека Synapse Ararat. Она уже применялась для подключения к Ардуино по последовательному порту. Это описывалось в статьях о передаче информации в текстовой и бинарной форме.
Скачать библиотеку можно из официального репозитория. Для подключения необходимых функций достаточно скопировать следующие файлы в папку с проектом:

  • blcksock.pas
  • synacode.pas
  • synafpc.pas
  • synaip.pas
  • synautil.pas
  • synsock.pas
  • sswin32.inc (для windows)

Порядок организации связи

Для осуществления связи делаем следующие процедуры:

  1. Подключаем модуль blcksock
  2. Создаем класс потока для прослушивания входящих сообщений
  3. Старт класса прослушивания порта (сервера)
  4. Процесс получения сообщения
  5. Процесс передачи сообщения
  6. Освобождение памяти потока сервера

Подключаем модуль blcksock

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

uses
  ....,  blcksock; //модуль сетевых сокетов  

Он подключить все другие необходимые модули.

Создаем класс потока для прослушивания входящих сообщений

Для того, чтобы сервер смог ждать входящих сообщений и не тормозить основную программу, нужно создать параллельный поток. Для этого нужно объявить новый класс-наследник класса TThread — базового потока. Это делается в разделе type.

type

  { UDPServer }
  // Класс для прослушивания порта в отдельном потоке
  TUDPServer = class(TThread)
  private
      FSocket:TUDPBlockSocket; // объект UDP сокета приема
      message: String;         // принятое сообщение
  protected
       procedure Execute;override; // Функция ожидания сообщения параллельно
       procedure TakeMessage;      // Функция передачи сообщения основной программе
  end;

В нем объявляется переменные для доступа к порту UDP сокета, принятого сообщения и функции проверки порта, отправки принятого сообщения основной программе.

Старт класса прослушивания порта (сервера)

Здесь нужно выполнить два условия: 1. создать глобальную переменную в разделе var для доступа к потоку сервера, 2. выделить для него память и запустить, например при нажатии на кнопку или при старте программы.

var // глобальный раздел переменных
	...
  Server : TUDPServer; // объект UDP сервера  

implementation   
...
//Где-то в программе, например в функции нажатии на кнопку
    Server:=TUDPServer.Create(True);// Создание объекта сокета
    Server.Priority:=tpNormal; // Приоритет использования профессора
    Server.Start;             // Запуск прослушивания порта
	

Процесс получения сообщения

Здесь наполняются две функции созданного класса TUDPServer.
Первая — Execute открывает сокет, его привязка к локальному IP и порту.
Причем если указать номер порта прослушивания sPort один, а отправки — другой, то можно выделить главную и подчиненные приложения. Главная — посылает сообщение подчиненным и наоборот.
Вторая — TakeMessage обращается к элементам основной программы для передачи принятого сообщения.

// Ожидание сообщений
procedure TUDPServer.Execute;
var S: string;
begin
  FSocket:=TUDPBlockSocket.Create; // Создание объекта сокета
  try
    FSocket.EnableReuse(True);//включаем режим повторного использования адреса
    FSocket.Bind(FSocket.LocalName,sPort);//привязываем сокет к адресу
    if FSocket.LastError<>0 then //во время привязки произошла ошибка
      begin
        message:='Ошибка запуска сервера';
        Synchronize(@TakeMessage); // Вызов функции отправки сообщения
        Exit;
      end;
    while not Terminated do  // Цикл до завершения потока
      begin
        S:=FSocket.RecvPacket(10); //пробуем получить пакет
        if S<>'' then // Если что-то принято
        begin
          message:=S; //пакет получен - обрабатываем
          Synchronize(@TakeMessage); // Вызов функции отправки сообщения
        end;
      end;
  finally
    FSocket.Free; // Освобождение сокета
  end;
end;
// Получение сообщений
procedure TUDPServer.TakeMessage;
begin
      Form1.Memo1.Append(message); // Обращение к элементам формы
end; 

Процесс передачи сообщения

Для передачи сообщения другой программе (серверу) можно создать новый UDP сокет, а затем есть два пути — соединить с конкретным IP для приватной передачи или выбрать широковещание (EnableBroadcast(True)), тогда тут устанавливается маска IP.
Порт для передачи cPort выбирается таким, на котором где-то запущено его прослушивание (сервер).
Для удобства приводится готовая функция отправки сообщения обеими методами. MessageText — текст сообщения, IP — указывается адрес получателя или пустую строку », в таком случае будет использоваться маска широковещания BrodcastIP (которую нужно указать напрямую, константой или из формы).

// Отправка сообщения
procedure TForm1.SendMessage(MessageText: string; IP:string);
var s: string;
    SendSock: TUDPBlockSocket;
begin
  S:=Format('%s:%s',[User.Text,MessageText]);
  SendSock:=TUDPBlockSocket.Create;
  try
    SendSock.createsocket;
    if IP='' then // отправка всем
      begin
        SendSock.EnableBroadcast(True);
        SendSock.Connect(BrodcastIP,cPort);
      end
    else
      SendSock.Connect(IP,cPort);//отправить отдельно по IP
    SendSock.SendString(s);
    //if SendSock.LastError<>0 then
       // Обработка ошибки
	   
  finally
    SendSock.Free;
  end;
end; 

Чтобы отправить сообщение нужно просто вызвать эту функцию где-то в программе.

SendMessage('Сообщение','');//Отправка сообщения всем

SendMessage('Сообщение','192.168.0.3');//Отправка сообщение конкретному IP, например 192.168.0.3

Освобождение памяти потока сервера

При остановке сервера лучше очистить занимаемую сервером память.

// Остановка сервера
Server.Terminate; // Остановить поток сервера
Server.WaitFor;   // Ожидание окончания процессов
Server.Free;      // Освобождение памяти

Пример UDP клиент-сервера — чат

Для понимания полной картины работы с UDP сокетов в Lazarus, была разработана программа сетевого чата.
Этот проект можно использовать как шаблон или даже как самостоятельное приложение сетевого чата. Для этого нужно просто запустить приложение несколько раз и правильно настроить (показано в видео).

Внимание! Если у вас активен Firewall, то нужно будет одобрить новое соединение.

Интерфейс программы выглядит так:

Как передать информацию по сети (UDP сокеты в Lazarus)

Программа пример использования UDP сокетов для передачи информации по сети

Скачать исходники на GitHUB

Использование:

  1. Ввести имя пользователя (оно будет включено в сообщение)
  2. Ввести IP маску для широковещания по умолчанию — всем.
  3. Ввести номера портов для приема и передачи
  4. Нажать кнопку старт сервера (сделать тоже на других копиях)
  5. Ввести сообщение в верхнее поле и нажать Отправить.
  6. При приходе сообщения от другой программы по порту приема — сообщение отобразится в поле ниже.
Как передать информацию по сети (UDP сокеты в Lazarus)

Видеопрезентация

Подписывайтесь на группу ВК и канал YouTube, чтобы не пропустить обновления.

(с) Исаков Роман В., 2022