简体   繁体   中英

Choosing multicast network interface in Python

I have a server with two separate Ethernet connections. When I bind a socket in python it defaults to one of the two networks. How do I pull a multicast stream from the second network in Python? I have tried calling bind using the server's IP address on the second network, but that hasn't worked.

I recommend you don't use INADDR_ANY. In production multicast environments you want to be very specific with your multicast sockets and don't want to be doing things like sending igmp joins out all interfaces. This leads to hack-job workarounds when things aren't working like "route add -host 239.1.1.1 dev eth3" to get multicast joins going correctly depending on the system in question. Use this instead:

def joinMcast(mcast_addr,port,if_ip):
    """
    Returns a live multicast socket
    mcast_addr is a dotted string format of the multicast group
    port is an integer of the UDP port you want to receive
    if_ip is a dotted string format of the interface you will use
    """

    #create a UDP socket
    mcastsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    #allow other sockets to bind this port too
    mcastsock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

    #explicitly join the multicast group on the interface specified
    mcastsock.setsockopt(socket.SOL_IP,socket.IP_ADD_MEMBERSHIP,
                socket.inet_aton(mcast_addr)+socket.inet_aton(if_ip))

    #finally bind the socket to start getting data into your socket
    mcastsock.bind((mcast_addr,port))

    return mcastsock

In the mcastsock.bind you can also use '' instead of the address string, but I advise against this. With '', if you have another socket using the same port, both sockets will get eachothers data.

When bind ing your socket, try the values mentioned here :

For IPv4 addresses, two special forms are accepted instead of a host address: the empty string represents INADDR_ANY, and the string '' represents INADDR_BROADCAST.

INADDR_ANY is also known as the wildcard address:

Sockets with wildcarded local addresses may receive messages directed to the specified port number and addressed to any of the possible addresses assigned to a host`

More here .

I figured it out. It turns out that the piece I was missing was adding the interface to the mreq structure that is used in adding membership to a multicast group.

For IPv4, the index of the network interface is the IP address; for IPv6 the index of the network interface is returned by the method socket.getaddrinfo.

The code below shows how to listen to multicast on all network interfaces:

from socket import AF_INET6, AF_INET
import socket
import struct

# Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant
if not hasattr(socket, 'IPPROTO_IPV6'):
    socket.IPPROTO_IPV6 = 41

multicast_address = {
    AF_INET: ["224.0.1.187"],
    AF_INET6: ["FF00::FD"]
}
multicast_port = 5683

addr_info = socket.getaddrinfo('', None)  # get all ip
for addr in addr_info:
    family = addr[0]
    local_address = addr[4][0]

    sock = socket.socket(family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((local_address, multicast_port))
    if family == AF_INET:
        for multicast_group in multicast_address[family]:
            sock.setsockopt(
                socket.IPPROTO_IP,
                socket.IP_ADD_MEMBERSHIP,
                socket.inet_aton(multicast_group) + socket.inet_aton(local_address)
            )
    elif family == AF_INET6:
        for multicast_group in multicast_address[family]:
            ipv6mr_interface = struct.pack('i', addr[4][3])
            ipv6_mreq = socket.inet_pton(socket.AF_INET6, multicast_group) + ipv6mr_interface
            sock.setsockopt(
                socket.IPPROTO_IPV6,
                socket.IPV6_JOIN_GROUP,
                ipv6_mreq
            )
# _transport, _protocol = await loop.create_datagram_endpoint(
#     lambda: protocol_factory(), sock=sock)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM