IP Multicast + UDP: я должен получить данные для всех групп? - PullRequest
0 голосов
/ 05 февраля 2019

Каково правильное поведение IP Multicast по UDP?

Представьте себе следующий сценарий:

  1. Мы пытаемся поговорить с IP-протоколом по UDP.
  2. Мы открываем сокет UDP с определенным портом (например, 60001)
  3. Затем мы присоединяем сокет к некоторой многоадресной группе (например, 239.192.0.1)
  4. Мы открываем еще один сокет UDP с портом 60002
  5. Затем мы присоединяем сокет к другой многоадресной группе (например, 239.192.0.2)

Когда это делается в Windows, с Winsock каждый сокет становится данными только при выполнении обоих условий:

  • Совпадения портов UDP
  • и совпадения групп многоадресной рассылки.

Вот код Delphi для этого:

procedure Connect();
var err: Integer;
    wData: WsaData;
    reuse: Integer;
begin
  FillChar(wData, SizeOf(wData), 0);
  err := WSAStartup(MAKEWORD(2, 2), wData);
  if err = SOCKET_ERROR then Exit;

  _fd := socket(AF_INET, SOCK_DGRAM, 0);
  if _fd = INVALID_SOCKET then Exit;

  reuse := 1;
  if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, Pointer(@reuse), SizeOf(reuse)) < 0) then Exit;

  FillChar(_addr, sizeof(_addr), 0);
  _addr.sin_family := AF_INET;
  if (_listeningInterface = '0.0.0.0') or not _isIpAddress(_listeningInterface) then
    _addr.sin_addr.s_addr := htonl(INADDR_ANY)
  else
    _addr.sin_addr.s_addr := inet_addr(PAnsiChar(_listeningInterface));
  _addr.sin_port := htons(_port);

  if (bind(_fd, _addr, sizeof(_addr)) < 0) then Exit;

  if _isMulticast() then begin
    _mreq.imr_multiaddr.s_addr := inet_addr(PAnsiChar(_multicastGroup));
    if (_listeningInterface = '0.0.0.0') or not _isIpAddress(_listeningInterface) then
      _mreq.imr_interface.s_addr := htonl(INADDR_ANY)
    else
      _mreq.imr_interface.s_addr := inet_addr(PAnsiChar(_listeningInterface));
    // Joinig multicast group here. Note the _fd variable usage here.
    if (setsockopt(_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, @_mreq, sizeof(_mreq)) < 0) then Exit;
  end;
end;

Когда мы пытаемся сделать это из библиотеки Keil для микроконтроллеров, для этого нет функции, подобной setsockopt.Существует функция igmp_join, которая не принимает переменную сокета, но только для группы многоадресной рассылки.

В результате мы не можем указать соответствие порта UDP и группы многоадресной рассылки, и каждый сокет UDP становится данными для всех групп.мы присоединились к.

Какой из двух подходов является правильным: Keil's или Windows '?

1 Ответ

0 голосов
/ 08 февраля 2019

Оба поведения верны.

Какие пакеты UDP вы получаете, по какому сокету выходит за рамки определения многоадресной рассылки IPv4.

Ожидание того, что вы получите только трафик, для которого вы присоединились к группе, часто нарушается.Кроме того, все операционные системы реализуют это по-разному.Linux и Windows ведут себя по-разному, а небольшие стеки IP в микроконтроллерах обычно ведут себя еще проще.

Исходный уровень, наихудший случай, который вы можете ожидать, таков: вы будете получать случайные пакеты UDP на своем сокете UDP, даже от групп, к которым вы не присоединились.Но на практике это обычно не так уж плохо.Просто в качестве ориентира, когда думаешь об этом.Причина в том, что ОС может задержать прекращение членства.Локальные маршрутизаторы будут задерживать отбрасывание членства.Локальные маршрутизаторы будут содержать ошибки.

Вам все равно придется иметь дело с получением неожиданных пакетов UDP, поскольку любой в вашей сети может подделывать пакеты UDP и отправлять их в ваш сокет от имени другого лица.Также любой может подделать пакеты IGMP и «присоединить вас» к любым группам многоадресной рассылки.

Это означает: на практике вам всегда нужно выполнять фильтрацию на уровне приложений и молча игнорировать неожиданные пакеты UDP.В большинстве стеков IP существует (нетривиальная) опция для определения адреса назначения полученного пакета UDP.Это наиболее полезно для разделения трафика для нескольких групп многоадресной рассылки.

И так как теперь вы знаете поведение своего стека IP, вы можете, например, сохранить некоторую память и просто использовать один сокет UDP для получения всего трафика UDP.и демультиплексировать его на стороне приложения.Конечно, все зависит от вашего приложения.

Но да, я понимаю, вы разочарованы тем, что многоадресная рассылка IP так недооценена.Я чувствую себя с тобой!: -)

...