你如何在Python中UDP多播?

81 python multicast

如何在Python中发送和接收UDP多播?有标准库吗?

Gor*_*ley 89

这对我有用:

接收

import socket
import struct

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
IS_ALL_GROUPS = True

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
    # on this port, receives ALL multicast groups
    sock.bind(('', MCAST_PORT))
else:
    # on this port, listen ONLY to MCAST_GRP
    sock.bind((MCAST_GRP, 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)
Run Code Online (Sandbox Code Playgroud)

发送

import socket

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after two hops on the network the packet will not 
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 2

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
Run Code Online (Sandbox Code Playgroud)

它基于http://wiki.python.org/moin/UdpCommunication中不起作用的示例.

我的系统是... Linux 2.6.31-15-generic#50-Ubuntu SMP Tue 11月10日14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4

  • 对于mac os x,您需要使用socket.SO_REUSEPORT选项作为上例中socket.SO_REUSEADDR的替代选项,以允许同一多播端口地址组合上的多个侦听器. (6认同)
  • 对于udp多播,你需要绑定到多播组/端口而不是本地组端口,`sock.bind((MCAST_GRP,MCAST_PORT))`,你的代码可能也可能不起作用,当你有多个网络时它可能不起作用 (2认同)
  • @RandallCook:当我用MCAST_GRP替换''时,我得到socket.error:[Errno 10049]请求的地址在其上下文中无效 (2认同)

小智 17

广播到组播组的组播发送方:

#!/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()
Run Code Online (Sandbox Code Playgroud)

从多播组读取并将十六进制数据打印到控制台的多播接收器:

#!/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()
Run Code Online (Sandbox Code Playgroud)

  • 您需要绑定到多播组/端口而不是多播地址上的本地端口, `sock.bind((MCAST_GRP, MCAST_PORT))` (2认同)

st0*_*0ne 12

更好用:

sock.bind((MCAST_GRP, MCAST_PORT))
Run Code Online (Sandbox Code Playgroud)

代替:

sock.bind(('', MCAST_PORT))
Run Code Online (Sandbox Code Playgroud)

因为,如果要在同一端口上侦听多个多播组,您将获得所有侦听器上的所有消息.


小智 7

为了加入多播组,Python 使用原生 OS 套接字接口。由于 Python 环境的可移植性和稳定性,许多套接字选项直接转发到本地套接字 setsockopt 调用。组播操作模式,例如加入和删除组成员身份,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)
Run Code Online (Sandbox Code Playgroud)

首先它创建套接字,绑定它并通过发出setsockopt. 最后它永远接收数据包。

发送组播 IP 帧很简单。如果您的系统中有单个 NIC,则发送此类数据包与通常的 UDP 帧发送没有区别。您只需要在sendto()方法中设置正确的目标 IP 地址即可。

我注意到很多关于互联网的例子实际上是偶然的。即使在官方python文档中。他们所有人的问题都在错误地使用 struct.pack。请注意,典型示例使用4slas 格式,它与实际的 OS 套接字接口结构不一致。

我将尝试描述在对 python 套接字对象执行 setsockopt 调用时会发生什么。

Python 将 setsockopt 方法调用转发到本机 C 套接字接口。Linux 套接字文档(请参阅参考资料man 7 ip)介绍ip_mreqn了 IP_ADD_MEMBERSHIP 选项的两种结构形式。最短的格式是 8 字节长,较长的是 12 字节长。上面的示例生成 8 字节setsockopt调用,其中前四个字节定义multicast_group,第二个四个字节定义interface_ip