在Python中的多播
你如何在Python中发送和接收UDP多播? 有没有一个标准的图书馆这样做?
这适用于我:
接收
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-generic#50 -Ubuntu SMP Tue Nov 11 10:01:20 UTC 2009 i686 GNU / Linux Python 2.6.4
广播到多播组的多播发送者:
#!/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()
从多播组中读取并将hex数据打印到控制台的多播接收器:
#!/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()
更好地使用:
sock.bind((MCAST_GRP, MCAST_PORT))
代替:
sock.bind(('', MCAST_PORT))
…因为如果你想听同一个端口上的多个mcast组,你将在所有的监听器上得到所有的消息
看看py-multicast 。 networking模块可以检查一个接口是否支持多播(至less在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的问题是由不支持多播的接口引起的?
http://twistedmatrix.com/trac/有一个框架可以做到这一点。; 以下是示例https://twistedmatrix.com/documents/12.2.0/core/howto/udp.html
为了join多播组,Python使用本地OS套接字接口。 由于Python环境的可移植性和稳定性,许多套接字选项被直接转发到本地套接字setsockopt调用。 join和删除组成员的多播操作模式只能通过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)
首先它创build套接字,绑定它并通过发出setsockopt
触发触发器组join。 在最后它永远接收数据包。
发送组播IP帧非常简单。 如果系统中有单个NIC,则发送此类数据包与通常的UDP帧发送没有区别。 所有你需要照顾的只是在sendto()
方法中设置正确的目标IP地址。
我注意到很多互联网上的例子其实都是偶然的。 即使在官方的Python文档。 问题都是使用struct.pack不正确。 请注意,典型的例子使用4sl
作为格式,它不符合实际的OS套接字接口结构。
我将尝试描述在执行用于python套接字对象的setsockopt调用时发生的问题。
Python将setsockopt方法调用转发给本地C套接字接口。 Linux套接字文档(请参见man 7 ip
)为IP_ADD_MEMBERSHIP选项引入了两种forms的ip_mreqn
结构。 最短的forms是8个字节长,更长的是12个字节长。 上面的例子生成8字节setsockopt
调用,其中字节的拳头定义了multicast_group
和第二个interface_ip
。
除IP地址以外,组播stream量与普通UDP没有区别。 看看标准套接字库 。 您可能能够findbuild立在套接字上的东西,并且更易于使用。
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)
要使客户端代码(从tolomea)在Solaris上工作,您需要将IP_MULTICAST_TTL
套接字选项的ttl值作为无符号字符传递。 否则,你会得到一个错误。 这在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))