Работа с UDP в Delphi

Cети и Интернет   4 Февраль 2012  Автор статьи: admin 

Скачать пример работы с UDP + модуль, значительно упрощающий работу с UDP.

В этой статье мы рассмотрим основные принципы работы с транспортным протоколом UDP в Delphi, а также все плюсы и минусы UDP по сравнению с TCP.
Для начала рассмотрим саму суть транспортного механизма UDP.
UDP (англ. User Datagram Protocol — протокол пользовательских датаграмм) позволяет осуществлять передачу данных без предварительной установки соединения. По сравнению с TCP, UDP не может гарантировать доставку пакета с информацией, что позволяет ему гораздо быстрее доставлять данные. UDP выгодно использовать в приложениях, где происходит очень частая отправка данных, т.е. где требуется высокая пропускная способность линии связи.
Приступим к созданию простого примера работы с UDP.
Для начала подключим модуль WinSock, который позволяет работать с сокетами.
Объявим тип, которым будут представлены пакеты передаваемых данных:

1
2
3
4
TPacket = packed record
    mode: byte;
    pack: array [0 .. 9999] of Char;
  end;

Для примера я объявил запись, состоящую из mode и pack. Передаваемые пакеты могут быть и такими. Такие пакеты очень удобно обрабатывать при получении, т.к. их структура нам будет уже ясна.
Объявим следующие глобальные переменные:

1
2
3
4
5
var
  Sock: TSocket; // сокет
  ServerAddr: TSockAddrIn; // здесь будет храниться информация
  // для взаимодействия между приложениями
  wData: TWSAData;

Теперь приступим непосредственно к инициализации сокета:

1
2
3
4
5
6
7
8
9
10
11
procedure InitUDP;
begin
  WSAStartup($0101, wData);
  Sock := socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); // SOCK_DGRAM означает,
  // что мы будем работать с транспортным протоколом UDP
  ServerAddr.sin_family := AF_INET;
  ServerAddr.sin_port := htons(666);
  bind(Sock, ServerAddr, SizeOf(ServerAddr));
  CreateThread(nil, 0, @RecvProc, nil, 0, LongWord(nil^));
  // здесь мы создаем поток, в котором реализуем получение пакетов
end;

Теперь реализуем поток, который будет осуществлять прием данных:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure RecvProc(Param: Pointer); stdcall;
var
  Count: LongInt;
  from: TSockAddrIn;
  FromLen: LongInt;
  Packet: TPacket;
  i, j: LongInt;
begin
  while True do // зацикливаем поток
  begin
    FromLen := SizeOf(from);
    Count := recvfrom(Sock, Packet, SizeOf(Packet), 0, from, FromLen); // считываем данные
    if Count > 0 then
    begin
      ExecutePacket(Packet{сам пакет},
         string(inet_ntoa(from.sin_addr)){IP-адрес отправителя пакета});
    end;
  end;
end;

В этом потоке мы получаем пакет, IP адрес отправителя этого пакета и передаем эти данные процедуре ExecutePacket, которая будет обрабатывать полученную информацию. В нашем случае мы просто выведем на экран содержимое полученного пакета в виде обыкновенного сообщения:

1
2
3
4
5
procedure ExecutePacket(pack: TPacket{сам пакет};
from: AnsiString{IP-адрес отправителя пакета});
begin
  ShowMessage(pack.pack);
end;

Теперь реализуем отправку пакета с данными. Реализуем следующую процедуру:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
procedure SendToIP(fip: AnsiString; fpack: string; fmode: byte);
  procedure Send(var Packet: TPacket; var Addr: TSockAddrIn);
  // эта процедура реализует непосредственную отправку собранного пакета
  // по указанным в Addr данным
  begin
    sendto(Sock, Packet, SizeOf(Packet), 0, Addr, SizeOf(Addr));
  end;
var
  PacketToSend: TPacket; // собираемый пакет
  i: integer;
begin
  ServerAddr.sin_port := htons(666);
  ServerAddr.sin_addr.S_addr := inet_addr(PAnsiChar(fip)); // указываем IP получателя пакета
  PacketToSend.mode := fmode; // собираем пакет
  PacketToSend.pack := #0; // необходимо работать не с типом string, а array of char.
  // поэтому преобразуем string в array of char следующим образом:
  for i := 0 to length(fpack) - 1 do
    PacketToSend.pack[i] := Char(fpack[i + 1]);
  // отправляем собранный пакет
  Send(PacketToSend, ServerAddr);
end;

Ну, и наконец, реализуем процедуру закрытия сокета:

1
2
3
4
5
procedure DestroyUDP;
begin
  closesocket(Sock);
  WSACleanup;
end;

Таким образом можно реализовать работу с транспортным протоколом UDP. Вы также можете скачать рабочий пример. К этому примеру прилагается модуль, позволяющий реализовывать работу с UDP в 3 строки программного кода абсолютно без каких-либо затруднений. Работать с таким модулем гораздо легче и удобнее. Скачать все это вы можете отсюда.

  • Дмитрий

    При всем уважении, я понимаю когда в примерах не пишут проверок на ошибки (хотя даже тогда принято пояснять для новичков, что проверки опущены для краткости), но когда предлогают «готовый модуль» без них это уже перегиб. А уж незавершенный поток в принципе не иеющий точки выхода это отдельный перл.

  • Евгений

    Здравствуйте, я начинающий. А как чтение организовать с конкретного ip?

Научиться программировать

  • на Delphi

  • на Java

  • на C++