How do you UDP multicast in Python?

2019-01-03 01:11发布

How do you send and receive UDP multicast in Python? Is there a standard library to do so?

10条回答
放荡不羁爱自由
2楼-- · 2019-01-03 01:53

Multicast traffic is no different than regular UDP except for the IP address. Take a look at the standard socket library. You may be able to find something that builds on socket and is easier to use.

查看更多
何必那么认真
3楼-- · 2019-01-03 01:54

tolomea's answer worked for me. I hacked it into socketserver.UDPServer too:

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)
查看更多
贪生不怕死
4楼-- · 2019-01-03 01:58

Multicast sender that broadcasts to a multicast group:

#!/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()

Multicast receiver that reads from a multicast group and prints hex data to the console:

#!/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()
查看更多
ゆ 、 Hurt°
5楼-- · 2019-01-03 01:59

Better use:

sock.bind((MCAST_GRP, MCAST_PORT))

instead of:

sock.bind(('', MCAST_PORT))

because, if you want to listen to multiple multicast groups on the same port, you'll get all messages on all listeners.

查看更多
地球回转人心会变
6楼-- · 2019-01-03 02:01

Have a look at py-multicast. Network module can check if an interface supports multicast (on Linux at least).

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

Perhaps problems with not seeing IGMP, were caused by an interface not supporting multicast?

查看更多
放我归山
7楼-- · 2019-01-03 02:02

In order to Join multicast group Python uses native OS socket interface. Due to portability and stability of Python environment many of socket options are directly forwarded to native socket setsockopt call. Multicast mode of operation such as joining and dropping group membership can be accomplished by setsockopt only.

Basic program for receiving multicast IP packet can look like:

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)

Firstly it creates socket, binds it and triggers triggers multicast group joining by issuing setsockopt. At very end it receives packets forever.

Sending multicast IP frames is straight forward. If you have single NIC in your system sending such packets does not differ from usual UDP frames sending. All you need to take care of is just set correct destination IP address in sendto() method.

I noticed that lot of examples around Internet works by accident in fact. Even on official python documentation. Issue for all of them are using struct.pack incorrectly. Please be advised that typical example uses 4sl as format and it is not aligned with actual OS socket interface structure.

I will try to describe what happen underneath the hood when exercising setsockopt call for python socket object.

Python forwards setsockopt method call to native C socket interface. Linux socket documentation (see man 7 ip) introduces two forms of ip_mreqn structure for IP_ADD_MEMBERSHIP option. Shortest is form is 8 bytes long and longer is 12 bytes long. Above example generates 8 byte setsockopt call where fist for bytes defines multicast_group and second interface_ip.

查看更多
登录 后发表回答