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

61

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

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

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

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

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

Ваш Ответ

4   ответа
5

го сокета RECEIVING.

Я согласен со всеми ответами выше относительно получения многоадресных сокетов. ОП отметил, что привязка разъема RECEIVING к интерфейсу не помогла. Однако необходимо привязать многоадресный сокет SENDING к интерфейсу.

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

  // 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 () из-за ошибки «Нет маршрута к хосту». Если кто-то может пролить свет на то, почему отключение DHCP-шлюза приводит к путанице в многоадресных SENDING-сокетах Mac OS X, я хотел бы услышать это.

52

ание адреса и порта, с которого следует получать данные (НЕ локальный интерфейс, как в случае с привязкой к TCP-получателю). Адрес, указанный в этом случае, имеетfiltering роль, то есть сокет будет принимать только дейтаграммы, отправленные на этот адрес многоадресной рассылки & amp; порт, независимо от того, к каким группам впоследствии присоединяется сокет. Это объясняет, почему при привязке к INADDR_ANY (0.0.0.0) я получал дейтаграммы, отправленные моей многоадресной группе, тогда как при привязке к любому из локальных интерфейсов я ничего не получал, даже если дейтаграммы отправлялись в сети, к которой этот интерфейс соответствует.

Цитирование из UNIX & # xAE; Сетевое программирование, Том 1, третье издание: API-интерфейс для сокетов от W.R. Stevens. 21,10. Отправка и получение

[...] We want the receiving socket to bind the multicast group and port, say 239.255.1.2 port 8888. (Recall that we could just bind the wildcard IP address and port 8888, but binding the multicast address prevents the socket from receiving any other datagrams that might arrive destined for port 8888.) We then want the receiving socket to join the multicast group. The sending socket will send datagrams to this same multicast address and port, say 239.255.1.2 port 8888.

Error: User Rate Limit Exceeded haelix
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededalways binding to "0.0.0.0" and specifying the interface address when joining the group, works very wellError: User Rate Limit Exceeded
45

& Quot; bind & quot; Операция в основном говорит: «Используйте этот локальный порт UDP для отправки и получения данных. он выделяет этот порт UDP для исключительного использования для вашего приложения. (То же самое относится и к сокетам TCP).

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

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

& Quot; присоединиться к многоадресной группе & quot; операция (IP_ADD_MEMBERSHIP), потому что он в основном говорит вашему сетевому адаптеру, что он должен прослушивать не только кадры Ethernet, где MAC-адрес назначения является вашим собственным, но также и адаптер Ethernet (NIC) прослушивать многоадресный IP-трафик, а также соответствующий многоадресный Ethernet-адрес. Каждый многоадресный IP-адрес сопоставляется с многоадресным Ethernet-адресом. Когда вы используете сокет для отправки на определенный IP-адрес многоадресной рассылки, для MAC-адреса назначения в кадре Ethernet устанавливается соответствующий MAC-адрес многоадресной рассылки для IP-адреса многоадресной рассылки. Когда вы присоединяетесь к группе многоадресной рассылки, вы настраиваете NIC для прослушивания трафика, отправляемого на тот же MAC-адрес (в дополнение к его собственному).

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

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

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

The IANA owns the OUI MAC address 01:00:5e, therefore multicast packets are delivered by using the Ethernet MAC address range 01:00:5e:00:00:00 - 01:00:5e:7f:ff:ff. This is 23 bits of available address space. The first octet (01) includes the broadcast/multicast bit. The lower 23 bits of the 28-bit multicast IP address are mapped into the 23 bits of available Ethernet address space.

Error: User Rate Limit Exceededbind(interfAddr, port)Error: User Rate Limit Exceeded haelix
Error: User Rate Limit ExceededlinkError: User Rate Limit Exceeded haelix
Error: User Rate Limit ExceededunicastError: User Rate Limit Exceeded haelix
Error: User Rate Limit Exceededtldp.org/HOWTO/Multicast-HOWTO-6.htmlError: User Rate Limit Exceeded
Error: User Rate Limit Exceededread()Error: User Rate Limit Exceeded haelix
10

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

The "bind" operation is basically saying, "use this local UDP port for sending and receiving data. In other words, it allocates that UDP port for exclusive use for your application

Есть одно исключение. Несколько приложенийcan использовать один и тот же порт для прослушивания (обычно это имеет практическое значение для многоадресных дейтаграмм), если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-датаграмма, полученная на этом общем порту, будет доставлена каждому из процессов (обеспечивая естественное соединение с многоадресным трафиком).

Вот дальнейшие детали относительно того, что происходит в нескольких случаях:

attempt of any bind ("exclusive" or "reuse") to free port will be successful

attempt to "exclusive binding" will fail if the port is already "reuse-binded"

attempt to "reuse binding" will fail if some process keeps "exclusive binding"

Похожие вопросы