Как вы отправляете и получаете многоадресную рассылку UDP в Python? Есть ли стандартная библиотека для этого?
Многоадресная рассылка в Python
Ответ 1
Это работает для меня:
Прием
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
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)) # use MCAST_GRP instead of '' to listen only
# to MCAST_GRP, not all groups on MCAST_PORT
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print sock.recv(10240)
Отправить
import socket
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
Он основан на примерах http://wiki.python.org/moin/UdpCommunication, которые не сработали.
Моя система... Linux 2.6.31-15-generiС# 50-Ubuntu SMP Вт 10 ноя 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4
Ответ 2
Многоадресный отправитель, который транслирует в группу многоадресной рассылки:
#!/usr/bin/env python
import socket
import struct
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.sendto('Hello World!', (MCAST_GRP, MCAST_PORT))
if __name__ == '__main__':
main()
Многоадресный приемник, который считывает из группы многоадресной передачи и печатает шестнадцатеричные данные в консоли:
#!/usr/bin/env python
import socket
import binascii
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except AttributeError:
pass
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
sock.bind((MCAST_GRP, MCAST_PORT))
host = socket.gethostbyname(socket.gethostname())
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(host))
sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_GRP) + socket.inet_aton(host))
while 1:
try:
data, addr = sock.recvfrom(1024)
except socket.error, e:
print 'Expection'
hexdata = binascii.hexlify(data)
print 'Data = %s' % hexdata
if __name__ == '__main__':
main()
Ответ 3
лучшее использование:
sock.bind((MCAST_GRP, MCAST_PORT))
вместо:
sock.bind(('', MCAST_PORT))
... потому что если вы хотите прослушивать несколько групп mcast на одном и том же порту, вы получите все сообщения для всех слушателей.
Ответ 4
Посмотрите py-multicast. Сетевой модуль может проверить, поддерживает ли интерфейс многоадресную рассылку (по крайней мере, на Linux).
import multicast
from multicast import network
receiver = multicast.MulticastUDPReceiver ("eth0", "238.0.0.1", 1234 )
data = receiver.read()
receiver.close()
config = network.ifconfig()
print config['eth0'].addresses
# ['10.0.0.1']
print config['eth0'].multicast
#True - eth0 supports multicast
print config['eth0'].up
#True - eth0 is up
Возможно, проблемы с отсутствием IGMP вызваны интерфейсом, не поддерживающим многоадресную рассылку?
Ответ 5
Существует основа для этого из http://twistedmatrix.com/trac/. Вот пример https://twistedmatrix.com/documents/12.2.0/core/howto/udp.html
Ответ 6
Хороший пример, который работает для меня:
http://svn.python.org/projects/stackless/trunk/Demo/sockets/mcast.py
Ответ 7
Чтобы присоединиться к многоадресной группе, Python использует собственный интерфейс сокетов ОС. Из-за переносимости и стабильности среды Python многие опции сокета напрямую перенаправляются на внутренний вызов socketockockt. Многоадресный режим работы, такой как объединение и отбрасывание членства в группе, может выполняться только с помощью setsockopt
.
Базовая программа для приема IP-пакета многоадресной передачи может выглядеть так:
from socket import *
multicast_port = 55555
multicast_group = "224.1.1.1"
interface_ip = "10.11.1.43"
s = socket(AF_INET, SOCK_DGRAM )
s.bind(("", multicast_port ))
mreq = inet_aton(multicast_group) + inet_aton(interface_ip)
s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, str(mreq))
while 1:
print s.recv(1500)
Во-первых, он создает сокет, связывает его и запускает объединение многоадресной группы путем выпуска setsockopt
. В самом конце он получает пакеты навсегда.
Отправка многоадресных IP-фреймов выполняется прямо. Если в вашей системе есть один сетевой адаптер, отправка таких пакетов не отличается от обычной отправки кадров UDP. Все, что вам нужно позаботиться, - это установить правильный IP-адрес назначения в методе sendto()
.
Я заметил, что множество примеров вокруг Интернета работает случайно. Даже на официальной документации на python. Проблема для всех из них неправильно использует struct.pack. Пожалуйста, имейте в виду, что типичный пример использует формат 4sl
в качестве формата и не совпадает с фактической структурой интерфейса сокета ОС.
Я попытаюсь описать, что происходит под капотом при использовании setockopt для вызова объекта сокета python.
Python пересылает метод setockopt на собственный интерфейс сокета. Документация к сокету Linux (см. man 7 ip
) представляет две формы структуры ip_mreqn
для параметра IP_ADD_MEMBERSHIP. Самая короткая форма составляет 8 байтов и длиннее 12 байтов. В приведенном выше примере генерируется 8-байтовый вызов setsockopt
, где кулак для байтов определяет multicast_group
и второй interface_ip
.
Ответ 8
Многоадресный трафик не отличается от обычного UDP, за исключением IP-адреса. Взгляните на стандартную библиотеку сокетов . Возможно, вы сможете найти что-то, что строится на сокете и проще в использовании.
Ответ 9
Ответ tolomea работал у меня. Я взломал его в socketserver.UDPServer:
class ThreadedMulticastServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
def __init__(self, *args):
super().__init__(*args)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
Ответ 10
Чтобы сделать клиентский код (из tolomea) работать в Solaris, вам необходимо передать значение ttl для опции сокета IP_MULTICAST_TTL
как unsigned char. В противном случае вы получите сообщение об ошибке.
Это работало для меня на Solaris 10 и 11:
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
ttl = struct.pack('B', 2)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))