2015-04-23 1 views
0

На сервере Ubuntu 14.04 у меня есть два процесса, каждый из которых прослушивает многоадресные сообщения на одном и том же порту, но из разных групп. Я бы не ожидал этого, но каждый видит трафик как из группы, которую они хотят, так и из другой группы.Почему многоадресные сообщения на одном и том же порту, но из разных групп объединены?

Насколько я могу судить, это известное поведение (хотя я бы назвал это проблемой). Я нашел this SO question, в котором приведены некоторые методы определения группы многоадресной передачи, данные которой получены, но она не отвечает на вопрос о том, почему это происходит в первую очередь. Я бы подумал, что базовый системный сетевой код будет отфильтровывать сообщения в многоадресных группах, которые я не пытаюсь получить.

Хотя я в основном работаю на C++, я могу предоставить простой код Python, чтобы продемонстрировать проблему. В одном окне терминала я слушаю многоадресную группу 239.1.1.1, порт 12345. В другом окне терминала на том же сервере слушаю многоадресную группу 239.2.2.2, а также порт 12345. На второй машине я передаю одно многоадресное сообщение на 239.1. 1.1: 12345, а другое сообщение - 239.2.2.2:12345.

На SVR3, передатчик:

[email protected]:~$ mcast_snd 239.1.1.1 12345 "from 1.1.1" 
multicasting from 1.1.1 to 239.1.1.1 port 12345 
[email protected]:~$ mcast_snd 239.2.2.2 12345 "from 2.2.2" 
multicasting from 2.2.2 to 239.2.2.2 port 12345 

На SVR2, окно 1, первый приемник:

[email protected]:~$ mcast_rcv 239.1.1.1 12345 
listening for multicast data on 239.1.1.1 port 12345 
received 10 bytes: from 1.1.1 
received 10 bytes: from 2.2.2 

На SVR2, терминал 2, а другой приемник:

[email protected]:~$ mcast_rcv 239.2.2.2 12345 
listening for multicast data on 239.2.2.2 port 12345 
received 10 bytes: from 1.1.1 
received 10 bytes: from 2.2.2 

Как вы можете видеть, оба приемника получают оба сообщения. Может кто-нибудь объяснить, почему это так? И если есть лучший способ настроить приемники, чтобы не получать сообщения от других групп, сообщите об этом тоже.

Для справки, вот код для mcast_rcv:

#!/usr/bin/python 

import socket 
import struct 
import sys 

if len(sys.argv) != 3: 
    print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>' 
    sys.exit(0) 

mcast_group = sys.argv[1] 
mcast_port = int(sys.argv[2]) 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('', mcast_port)) 
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY) 

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 

print 'listening for multicast data on', mcast_group, 'port', mcast_port 

while True: 
    msg = sock.recv(10240) 
    print 'received', len(msg), 'bytes:', msg 

А вот код mcast_snd:

#!/usr/bin/python 

import socket 
import sys 

if len(sys.argv) != 4: 
    print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>', '<mess 
age>' 
    sys.exit(0) 

mcast_group = sys.argv[1] 
mcast_port = int(sys.argv[2]) 
message = sys.argv[3] 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) 

print 'multicasting', message, 'to', mcast_group, 'port', mcast_port 

sock.sendto(message, (mcast_group, mcast_port)) 

ответ

1

Проблема решена. Мне нужно указать группу многоадресной передачи для привязки к получателю, а не только к порту. This SO question. Я оставил адрес '' в коде Python, или INADDR_ANY в моем C++. Я в основном говорю OS, что хочу получать все сообщения на этом порту независимо от группы. Система дает мне именно то, о чем я прошу, как это всегда бывает.

Если я заменю строку sock.bind(('', mcast_port)) на sock.bind((mcast_group, mcast_port)) в mcast_rcv, поведение будет таким, каким я ожидаю и хочу. Простое присоединение к группе многоадресной рассылки (sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)) недостаточно, чтобы отфильтровать не групповые сообщения на этом порту.

2

Основное отличие от Receving multiple multicast feeds on the same port - C, Linux - вы используете python.

В mcast_rcv можно включить фильтр отключить опцию IP_MULTICAST_ALL, позволяя INADDR_ANY так:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('', mcast_port)) 
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY) 

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 
# disable mc_all 
if hasattr(socket,'IP_MULTICAST_ALL') != True: 
    socket.IP_MULTICAST_ALL = 49 
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_ALL, 0) 

Как питона я использовал оленью кожу определить socket.IP_MULTICAST_ALL, это может быть необходимо, чтобы определить его.

+0

При поиске дополнительной информации возникли две связанные темы обсуждения.Включая их здесь, они могут быть интересны другим, которые хотят изучить тему и понять различия немного больше: [OpenJDK Discussion] (http://mail.openjdk.java.net/pipermail/net-dev/2013-May/ 006267.html) и [Redhat Discussion] (https://bugzilla.redhat.com/show_bug.cgi?id=231899) – John

+0

@John: вы нашли мое сообщение для redhat :) Существует также другая аналогичная запись в [live555 ] (http://lists.live555.com/pipermail/live-devel/2013-October/017478.html), я добавлю к оригиналу [ответ] (https://stackoverflow.com/a/20919920/3102264) – mpromonet