Подтвердить что ты не робот

Что значит связать сокет многоадресной рассылки (UDP)?

Я использую многоадресный UDP между хостами, которые имеют несколько сетевых интерфейсов. Я использую boost:: asio, и я смущен двумя операциями, которые получатели должны сделать: bind, а затем join-group.

Зачем вам нужно указывать локальный адрес интерфейса во время связывания, когда вы делаете это с каждой группой многоадресной рассылки, в которую вы вступаете?

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

Примечание. "join-group" - это оболочка поверх setsockopt(IP_ADD_MEMBERSHIP), которая, как задокументировано, может быть вызвана несколько раз в одном сокете для подписки на разные группы (по разным сетям?). Поэтому было бы разумно отказаться от вызова привязки и указать порт каждый раз, когда я подписываюсь на группу.

Из того, что я вижу, всегда привязывается к "0.0.0.0" и указывает адрес интерфейса при вступлении в группу, работает очень хорошо. Confused.

4b9b3361

Ответ 1

Чтобы связать сокет UDP при приеме многоадресной рассылки, укажите адрес и порт, из которых можно получать данные (НЕ локальный интерфейс, как это имеет место для привязки акцептора TCP). Указанный в этом случае адрес имеет фильтрацию, т.е. Сокет будет принимать только датаграммы, отправленные на этот многоадресный адрес и порт, независимо от того, к каким группам впоследствии присоединяется сокет. Это объясняет, почему при привязке к INADDR_ANY (0.0.0.0) я получал датаграммы, отправленные в мою группу многоадресной рассылки, тогда как при привязке к любому из локальных интерфейсов я ничего не получал, даже несмотря на то, что датаграммы отправлялись в сети, к которой этот интерфейс переписывались.

Цитата из UNIX® Network Programming Том 1, Третье издание: Сетевой интерфейс Sockets W.R Stevens. 21,10. Отправка и получение

[...] Мы хотим, чтобы принимающий сокет связывал группу многоадресной рассылки и порт, скажем, 239.255.1.2 порт 8888. (Напомним, что мы могли бы просто привязать подстановочный IP-адрес и порт 8888, но привязывая многоадресный адрес не позволяет сокету получать какие-либо другие датаграммы, которые могут приходят для порта 8888.) Затем мы хотим, чтобы принимающий сокет присоединиться к группе многоадресной передачи. Передающий сокет отправит дейтаграммы на этот же многоадресный адрес и порт, скажем, 239.255.1.2 порт 8888.

Ответ 2

Операция "привязка" в основном говорит: "Используйте этот локальный порт UDP для отправки и получения данных. Другими словами, он выделяет этот UDP-порт для исключительного использования для вашего приложения. (То же самое верно для TCP-сокетов).

Когда вы привязываетесь к "0.0.0.0" (INADDR_ANY), вы в основном говорите на уровне TCP/IP, чтобы использовать все доступные адаптеры для прослушивания и выбрать лучший адаптер для отправки. Это стандартная практика для большинства кодов сокетов. Единственный раз, когда вы не укажете 0 для IP-адреса, - это когда вы хотите отправлять/получать по определенному сетевому адаптеру.

Аналогично, если вы укажете значение порта 0 во время привязки, ОС назначит случайно доступный номер порта для этого сокета. Поэтому я ожидал бы для многоадресной передачи UDP, вы привязываетесь к INADDR_ANY по определенному номеру порта, на который ожидается отправка многоадресного трафика.

Операция "join multicast group" (IP_ADD_MEMBERSHIP) необходима, потому что она в основном говорит сетевому адаптеру прослушивать не только Ethernet-кадры, где MAC-адрес назначения является вашим собственным, он также сообщает, что адаптер ethernet (NIC) прослушивает IP многоадресный трафик, а также для соответствующего многоадресного Ethernet-адреса. Каждый IP-адрес многоадресной рассылки соответствует многоадресному Ethernet-адресу. Когда вы используете отправку сокета на конкретный IP-адрес многоадресной рассылки, MAC-адрес назначения в кадре ethernet устанавливается на соответствующий MAC-адрес многоадресной рассылки для IP-адреса многоадресной передачи. Когда вы присоединяетесь к группе многоадресной рассылки, вы настраиваете сетевой адаптер для прослушивания трафика, отправленного на тот же MAC-адрес (в дополнение к его собственному).

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

Если вы присоединяетесь к группе многоадресной рассылки, весь сетевой трафик для всех портов на этом IP-адресе будет получен NIC. Только трафик, предназначенный для вашего подключенного порта прослушивания, будет передан стек TCP/IP в ваше приложение. В отношении того, почему порты указаны во время многоадресной подписки - это потому, что IP-адрес многоадресной рассылки - это только IP-адрес. "ports" - это свойство верхних протоколов (UDP и TCP).

Вы можете узнать больше о том, как многоадресные IP-адреса сопоставляются с многоадресными адресами Ethernet на разных сайтах. Статья в Википедии примерно так же хороша:

IANA владеет MAC-адресом OUI 01: 00: 5e, поэтому многоадресная рассылка пакеты доставляются с использованием диапазона MAC-адресов Ethernet 01: 00: 5е: 00: 00: 00 - 01: 00: 5е: 7f: ff: ff. Это 23 бита доступных адресное пространство. Первый октет (01) включает широковещательную/многоадресную рассылку немного. Нижние 23 бита 28-битного IP-адреса многоадресной рассылки отображаются в 23 бита доступного адресного пространства Ethernet.

Ответ 3

Исправление для Что означает привязка многоадресного (udp) сокета?, пока оно частично верно при следующей цитате:

Операция "привязка" в основном говорит: "Используйте этот локальный порт UDP для отправки и получения данных. Другими словами, он выделяет этот UDP-порт для исключительного использования для вашего приложения

Есть один частный случай. Несколько приложений могут совместно использовать один и тот же порт для прослушивания (обычно это имеет практическое значение для многоадресных датаграмм), если применяется опция SO_REUSEADDR:

int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create UDP socket somehow
...
int set_option_on = 1;
// it is important to do "reuse address" before bind, not after
int res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on, 
    sizeof(set_option_on));
res = bind(sock, src_addr, len);

Если несколько процессов выполняли такую ​​ "привязку повторного использования", то каждая датаграмма UDP, полученная на этом общем порту, будет доставляться в каждый из процессов (обеспечивая естественный совлокальный с многоадресным трафиком).

a) попытка любого связывания ( "эксклюзивное" или "повторное использование" ) на свободный порт будет успешной

b) попытка "эксклюзивной привязки" завершится неудачно, если порт уже "привязан к повторному использованию"

c) попытка "повторно использовать привязку" не удастся, если какой-то процесс сохраняет "эксклюзивную привязку"

Ответ 4

Также очень важно различать многоадресный сок SENDING от многоадресного сокета RECEIVING.

Я согласен со всеми приведенными выше ответами относительно ПОЛУЧЕНИЯ многоадресных сокетов. OP отметил, что привязка RECEIVING skt к интерфейсу не помогла. Тем не менее, необходимо привязать многоадресный SENDING-сокет к интерфейсу.

Для SENDING многоадресного сокета на многодомном сервере очень важно создать отдельный сокет для каждого интерфейса, который вы хотите отправить. Для каждого интерфейса должен быть создан связанный SENDING skt.

  // This is a fix for that bug that causes Servers to pop offline/online.
  // Servers will intermittently pop offline/online for 10 seconds or so.
  // The bug only happens if the machine had a DHCP gateway, and the gateway is no longer accessible.
  // After several minutes, the route to the DHCP gateway may timeout, at which
  // point the pingponging stops.
  // You need 3 machines, Client machine, server A, and server B
  // Client has both ethernets connected, and both ethernets receiving CITP pings (machine A pinging to en0, machine B pinging to en1)
  // Now turn off the ping from machine B (en1), but leave the network connected.
  // You will notice that the machine transmitting on the interface with
  // the DHCP gateway will fail sendto() with errno 'No route to host'
  if ( theErr == 0 )
  {
     // inspired by 'ping -b' option in man page:      
     //      -b boundif
     //             Bind the socket to interface boundif for sending.
     struct sockaddr_in bindInterfaceAddr;
     bzero(&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     bindInterfaceAddr.sin_len = sizeof(bindInterfaceAddr);
     bindInterfaceAddr.sin_family = AF_INET;
     bindInterfaceAddr.sin_addr.s_addr = htonl(interfaceipaddr);
     bindInterfaceAddr.sin_port = 0; // Allow the kernel to choose a random port number by passing in 0 for the port.
     theErr = bind(mSendSocketID, (struct sockaddr *)&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     struct sockaddr_in serverAddress;
     int namelen = sizeof(serverAddress);  
     if (getsockname(mSendSocketID, (struct sockaddr *)&serverAddress, (socklen_t *)&namelen) < 0) {
        DLogErr(@"ERROR Publishing service... getsockname err");
     }
     else
     {
        DLog( @"socket %d bind, %@ port %d", mSendSocketID, [NSString stringFromIPAddress:htonl(serverAddress.sin_addr.s_addr)], htons(serverAddress.sin_port) );
     }

Без этого исправления многоадресная передача будет периодически получать sendto() errno "Нет маршрута к хосту". Если кто-то может пролить свет на то, почему отсоединение шлюза DHCP приводит к тому, что сокеты SENDING для многоадресной рассылки Mac OS X запутываются, я хотел бы услышать это.