2013-03-07 5 views
0

У меня есть аппаратное устройство, которое отправляет многоадресные данные в мою сеть. Я написал скрипт python, который получает данные и печатает их. Тем не менее, я обнаружил, что он работает только на моем ПК под управлением Windows XP и не работает на моем компьютере Ubuntu Linux 10.04. В Linux ничего не получено. Он просто обходит цикл while и никогда не получал никаких данных. Мой код размещен ниже. Вы можете понять, почему это не будет работать под Linux? Спасибо, Раб.Получение многоадресных UDP-дейтаграмм с помощью python в Linux

# Multicast client 
# Adapted from: http://chaos.weblogs.us/archives/164 
# on 05/03/2013 

import socket 

ANY = "0.0.0.0" 
MCAST_ADDR = "224.0.33.154" 
MCAST_PORT = 31800 

# Create a UDP socket 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 

# Allow multiple sockets to use the same PORT number 
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 

# Bind to the port that we know will receive multicast data 
sock.bind((ANY,MCAST_PORT)) 

# Tell the kernel that we are a multicast socket 
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) 

# Tell the kernel that we want to add ourselves to a multicast group 
# The address for the multicast group is the third param 
status = sock.setsockopt(socket.IPPROTO_IP, 
socket.IP_ADD_MEMBERSHIP, 
socket.inet_aton(MCAST_ADDR) + socket.inet_aton(ANY)); 

# setblocking(0) is equiv to settimeout(0.0) which means we poll the socket. 
# But this will raise an error if recv() or send() can't immediately find or send data. 
sock.setblocking(0) 

while 1: 
    try: 
     data, addr = sock.recvfrom(1024) 
    except socket.error as e: 
     pass 
    else: 
     print "From: ", addr 
     print "Data: ", data 

Вот некоторые пример вывода из компьютера Windows:

From: ('0.0.0.0', 31801) 
Data: EDCP 

Примечание удаленное аппаратное устройство не имеет IP-адрес и использует адрес 0.0.0.0

EDIT: Я теперь обнаружил, что это также не работает на моем ноутбуке Windows. Таким образом, это не похоже, что это специфично для ОС. Кроме того, я попытался запустить другой скрипт для отправки многоадресных данных на один и тот же многоадресный адрес и порт. Я могу отправить с одного ПК, и все остальные могут правильно получать мой сценарий получения. Но только мой один компьютер с ОС Windows способен принимать данные с рассматриваемого аппаратного устройства. Мне интересно, связано ли это с адаптерами ethernet или их конфигурацией. Может ли это быть связано с тем фактом, что устройство harware имеет IP-адрес 0.0.0.0 и что эти адаптеры ethernet и/или мой скрипт-получатель должны получать сообщения с этим адресом? Запуск Wireshark на ПК Linux отображает данные с аппаратного устройства.

+0

Судя по голосам, вы должны, вероятно, проверить http: // stackoverflow.com/questions/603852/multicast-in-python –

+0

@EeroAaltonen Я уже проверил этот пост и нашел код для работы между моими различными ПК. Но код получения по-прежнему не получит данные, отправленные аппаратным устройством, которое я хочу проанализировать (он использует адрес 0.0.0.0, и я думаю, что это может быть причиной проблемы). – robhem

ответ

0

Try привязки к адресу многоадресной группы вместо:

sock.bind((MCAST_ADDR,MCAST_PORT)) 

Кроме того, вам не нужно устанавливать групповой TTL на приемнике, что это для отправителей, а также по желанию.

+0

'sock.bind ((MCAST_ADDR, MCAST_PORT))' Результаты с ошибкой: запрошенный адрес недействителен в его контексте. Я думаю, что привязка к 0.0.0.0 верна, так как это говорит IP-уровню, чтобы использовать все доступные адаптеры для прослушивания. – robhem

+0

Я должен добавить 'sock.bind ((MCAST_ADDR, MCAST_PORT))' приводит к ошибке в Windows (а не в Linux). Но это не решило мою проблему. – robhem

+0

Да, время жить - только для отправителя. Благодарю. – robhem

0

Я боролся с этой проблемой в течение двух дней. Wireshark видел пакеты, но мой код этого не делал. Ни один из якобы «окончательных» ответов из разных источников не работал для меня. Ключ от https://serverfault.com/questions/163244/linux-kernel-not-passing-through-multicast-udp-packets.

Запуск «ip maddr» показал, что код, похожий на ваш, не добавлял многоадресный адрес в любой интерфейс. Я заставил его добавить smcroute (см. Ссылку выше). Еще нет радости. Пакеты имеют IP-адрес 172.22 ... Мой интерфейс 172.17 ... Я добавил адрес 172.22 к этому сетевому адаптеру. Бинго! Теперь мой код получил пакеты.

Теперь, как заставить программу работать без smcroute? Я прокомментировал вызовы setsockopt(). Все еще работал. Не удалось связать многоадресный адрес с smcroute - не удалось. Разобрал вызовы setsockopt() и заменил «ЛЮБОЙ» на мой адрес 172.22. Успех!

Резюме:

  1. Убедитесь, что вы имеете IP на том же сегменте сети входящих пакетов.
  2. Используйте этот адрес в вызове IP_ADD_MEMBERSHIP вместо INADDR_ANY.

Возможно, вам не нужно будет делать 2) если у вас только одна сетевая карта. У меня три, и я должен это сделать.

Если уместно, я использую Ubuntu 12.04. Мне не нужно было изменять какие-либо настройки по умолчанию /etc/sysctl.conf, как описано другими. Я попробовал их. Они не помогли, поэтому я верну их обратно к установкам по умолчанию.

+0

Спасибо за ваш вклад. Я рассмотрю эти вещи. – robhem

+0

Runniing 'ip maddr' показывает многоадресный адрес для eth0. – robhem

+0

Если я пытаюсь запустить 'sudo smcroute -d', я получаю' MC-Router IPv4 уже использующийся' и 'Kernel не поддерживает ошибки многоадресной маршрутизации'. Я подтвердил, что в конфигурации ядра включена многоадресная рассылка, как указано в вашей ссылке. Любой другой способ добавить IP к eth0? Для чего это стоит, я попробовал следующее: Я сделал 'rp_filter = 0' в'/proc/sys/net/ipv4/conf/all/rp_filter' и в '/ proc/sys/net/ipv4/conf/default/rp_filter' и в '/ etc/sysctl.d/10-network-security.conf'. Также uncommented 'net.ipv4.ip_forward = 1' в'/etc/sysctl.conf'. Еще нет радости. – robhem

Смежные вопросы