LINUX.ORG.RU

[проблема с bind]Прием мультикаста с разных ip, но одинаковых портов


0

0

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

  struct sockaddr_in socket_address = {0};
  uint8_t opt;
  struct sockaddr_in sin = {0};

  int sockfd =  socket( AF_INET, SOCK_DGRAM, 0 );

  opt = 1;
  setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, &window_size, sizeof(window_size) );
  setsockopt( sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));

  sin.sin_family = AF_INET;
  sin.sin_port = htons(port);
  sin.sin_addr.s_addr = INADDR_ANY;

  bind(sockfd, (struct sockaddr *) &sin, sizeof(struct sockaddr_in);

а потом присоединяю его к группе:

  struct ip_mreq mreq = {0};

  mreq.imr_multiaddr.s_addr = ip;
  mreq.imr_interface.s_addr = htonl(INADDR_ANY);

  setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq));
Один экземпляр такой программы работает прекрасно, но когда пытаешь запустить еще один, то bind пишет ошибку «Address already in use».

Пробовал для sockaddr_in указывать конкретный ip, а не INADDR_ANY. Не помогло.

★★

С описываемой проблемой никогда не сталкивался, но что-то подсказывает, что надо биндить один сокет на один порт и использовать recvfrom, чтобы различать разные multicast потоки.

А двум приложениям забиндиться на один и тот же адрес не получится.

linuxfan
()
Ответ на: комментарий от linuxfan

Адреса разные. Одинаковые лишь порты. VLC, к примеру, такое может. Но в их запутаном коде пока не разобрался.

kulti ★★
() автор топика
  uint8_t opt; 

  /* ... */

  setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 
  setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, &window_size, sizeof(window_size) ); 
  setsockopt( sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); 

setsockopt точно ошибок не вызывает? А то там ведь должен быть int, а не uint8_t. Попробуй так:

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int) {1},
                                sizeof(int));
И проверяй возвращаемое значение. Если (-1), то произошла ошибка.

Deleted
()
Ответ на: комментарий от Deleted

И не совсем понятен смысл в SO_BROADCAST.

Deleted
()
Ответ на: комментарий от Deleted

упс) SO_REUSEADDR не отрабатывал из-за uint8_t. И с чего я взял, что там беззнаковый инт...

kulti ★★
() автор топика
Ответ на: комментарий от kulti

>Адреса разные. Одинаковые лишь порты.

Сокет биндится к локальному адресу. Я правильно понимаю, что у тебя remote address разный? Адрес удаленной стороны ни на что не влияет и различать источники мультикаста ты сможешь только по IP отправителя.

Или у тебя IP мультикаста разные? То есть есть два потока вещания, один вещает на 224.1.1.1:12345, другой на 224.1.1.1:12345? В этом случае тебе в bind надо в качестве sin.sin_addr.s_addr указывать не INADDR_ANY, а конкретный IP мультикаст группы. Тогда все будет пучком.

Вроде бы эта ссылка подтверждает догадку:

In order to receive multicast datagrams, an application must bind to the port number to which multicast datagrams will be sent. If an application binds to the address INADDR_ANY, it may receive all datagrams that are sent to the port number. If the application binds to a multicast group address, it may receive only datagrams sent to that group and port number.

linuxfan
()
Ответ на: комментарий от linuxfan

А двум приложениям забиндиться на один и тот же адрес не получится.

Получится, специально для этого существует SO_REUSEADDR.

Deleted
()
Ответ на: комментарий от Deleted

>Получится, специально для этого существует SO_REUSEADDR

SO_REUSEADDR существует для того, чтобы можно было забиндится на сокет, находящийся в состоянии *_WAIT. Не веришь — попробуй запустить два sshd на одном и том же порту и IP (или скопипастить пример сервера из info libc).

linuxfan
()
Ответ на: комментарий от linuxfan

В этом случае тебе в bind надо в качестве sin.sin_addr.s_addr указывать не INADDR_ANY, а конкретный IP мультикаст группы. Тогда все будет пучком.

Нет, сокет надо цеплять именно на INADDR_ANY. Далее, если мы хотим присоединиться к группе прослушивания мультикаст-потока, который отправляется с любого сервера, то передаём через setsockopt+IP_ADD_MEMBERSHIP структуру ip_mreq с заполненным адресом мультикаст-группы. Если мы хотим слушать только поток от определённого сервера (видимо это и хочет получить автор темы), то берём структуру ip_mreq_source, заполняем в ней адрес мультикаст-группы _и_ адрес отправителя, затем передаём через setsockopt+IP_ADD_SOURCE_MEMBERSHIP.

Как-то так...

Deleted
()
Ответ на: комментарий от Deleted

http://www.unixguide.net/network/socketfaq/4.11.shtml

SO_REUSEADDR allows your server to bind to an address which is in a TIME_WAIT state. It does not allow more than one server to bind to the same address. It was mentioned that use of this flag can create a security risk because another server can bind to a the same port, by binding to a specific address as opposed to INADDR_ANY. The SO_REUSEPORT flag allows multiple processes to bind to the same address provided all of them use the SO_REUSEPORT option.

linuxfan
()
Ответ на: комментарий от linuxfan

SO_REUSEADDR существует для того, чтобы можно было забиндится на сокет, находящийся в состоянии *_WAIT. Не веришь — попробуй запустить два sshd на одном и том же порту и IP (или скопипастить пример сервера из info libc).

Ты путаешь юникаст и мультикаст. А у них логика работы сильно отличается.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.