我有一台带有两个独立以太网连接的服务器。当我在python中绑定套接字时,它默认为两个网络之一。如何从Python中的第二个网络中提取多播流?我曾尝试在第二个网络上使用服务器的IP地址调用bind,但这没有用。
答案 0 :(得分:12)
我建议你不要使用INADDR_ANY。在生产多播环境中,您希望对组播套接字非常具体,并且不希望像发送igmp连接所有接口那样。当事情不像“route add -host 239.1.1.1 dev eth3”那样工作时,这会导致黑客作业的变通方法,以便根据相关系统正确地进行多播连接。请改用:
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
在mcastsock.bind中你也可以使用''而不是地址字符串,但我建议不要这样做。使用'',如果你有另一个套接字使用相同的端口,两个套接字将获得每个数据。
答案 1 :(得分:1)
在bind
套接字时,请尝试提及的值here:
对于IPv4地址,有两种特殊形式 被接受而不是主持人 address:空字符串表示 INADDR_ANY和字符串 '' 代表 INADDR_BROADCAST。
INADDR_ANY
也称为通配符地址:
具有通配符本地地址的套接字可能会收到指向指定端口号的消息,并发送到分配给主机的任何可能地址。
更多here。
答案 2 :(得分:0)
我明白了。事实证明,我所缺少的部分是将接口添加到mreq结构中,该结构用于向多播组添加成员资格。
答案 3 :(得分:0)
对于IPv4,网络接口的索引是IP地址;对于 IPv6,网络接口的索引由 socket.getaddrinfo 方法返回。
下面的代码展示了如何在所有网络接口上监听多播:
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)