关于这段代码使用套接字接收多播,我的结论是否合理?
Are my conclusions reasonable about this code receiving multicast using socket?
基于堆栈中的 MC 接收器:
How do you UDP multicast in Python?
我想彻底明白是怎么回事。以下是我理解的和不理解的:
据我了解:socket_name = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
=> 使用 IP proto ver 4 创建套接字,它将使用 UDP 接收 MC 数据报。
socket_name.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
这个负责设置socket可以使用相同地址的参数
(在本例中为端口,因为 SO_REUSEADDR = SO_REUSEPORT 用于多播)。
(段落多播~How do SO_REUSEADDR and SO_REUSEPORT differ?)
if IS_ALL_GROUPS: socket_name.bind(('', MCAST_PORT))
表示如果 IS_ALL_GROUPS
为真,则将套接字绑定到任何地址,否则: socket_name.bind((MCAST_GRP, MCAST_PORT))
表示将套接字绑定到特定给定的 IP 地址。
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
表示将 IP 地址转换为二进制形式,socket_name.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
表示我们添加组成员,此行之后数据包开始到达。
但是有些事情我不明白。
为什么当我使用 IS_ALL_GROUPS = true
时 MCAST_GRP = '239.0.1.104'
程序可以启动并且当参数为 false 时,它没有绑定到特定的多播地址?我的逻辑是,当参数为真时,它绑定到他从 IGMP 加入消息中获得的任何 MCast 地址,当参数为假时,它绑定到特定的给定地址。我说得对吗?
我有一个分析比特率的多线程程序,我以列表的形式提供了多个地址。当我将 IS_ALL_GROUPS
设置为 false 时,程序可以正确打印出来,例如10.5, 4.5, 5.0
其中每个结果都是来自唯一地址的一个流的比特率,但是所有地址共享同一个端口 12345
。当我将 IS_ALL_GROUPS
设置为 true 时,程序汇总结果给出 20.0, 20.0, 20.0
,你知道可能是什么原因吗?
import socket
import struct
MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
IS_ALL_GROUPS = True
socket_name = 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
socket_name.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
socket_name.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 socket_name.recv(10240)
我认为有几件事正在发生:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
应该probably be:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
唯一基于 "datagram" 的 IPv4 协议是 UDP,协议字段仅用于 "raw sockets",它被 tcpdump
等程序使用。不过这不重要。
下一个:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
只允许多个套接字一次绑定到相同的 (addr, port)
组合,即您可以一次 运行 程序的多个副本,或快速连续。我想这就是你所说的
下一个:
sock.bind((host, port))
表示您想接收发往给定地址和端口的数据包。特殊地址 ''
(即 INADDR_ANY
)意味着内核不应该对地址进行任何过滤。您可能不想在此阶段绑定到任何特定地址,请参阅 What does it mean to bind a multicast (UDP) socket?
下一个:
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
我建议使用 "=4sl"
作为格式字符串,因为这给了我 8 个字节,而不是 16 个字节,并且与我 (Linux) 上的 C struct ip_mreq
一致系统。这种填充差异可能只是一个 32/64 位问题,而且似乎没有什么坏处
总结一下:1. setsockopt(IP_ADD_MEMBERSHIP)
调用要求您的内核网络堆栈安排(通过 IGMP)将发送到 MCAST_GRP
的多播数据包传送到连接到您主机的网络接口. 2. bind()
调用已安排通过网络接口接收到的数据包到达进程中的套接字。 bind()
指定 INADDR_ANY
可能很重要,这样所有到达的多播数据包都会传送到您的进程而不是被过滤
一些可能有用的命令行是:
tcpdump -i eth0 -vv 'ip proto 2'
转储 IGMP 数据包,并且:
tcpdump -i eth0 -vv 'net 224.0.0.0/4'
转储多播数据包
我不确定你的 "multithread analysis program" 在做什么,因为你没有提供任何相关信息。你发的代码也不对,大概socket_name
和sock
是一样的吧?我还建议使用 Python 3 因为 Python 2 快死了
基于堆栈中的 MC 接收器: How do you UDP multicast in Python?
我想彻底明白是怎么回事。以下是我理解的和不理解的:
据我了解:socket_name = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
=> 使用 IP proto ver 4 创建套接字,它将使用 UDP 接收 MC 数据报。
socket_name.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
这个负责设置socket可以使用相同地址的参数
(在本例中为端口,因为 SO_REUSEADDR = SO_REUSEPORT 用于多播)。 (段落多播~How do SO_REUSEADDR and SO_REUSEPORT differ?)
if IS_ALL_GROUPS: socket_name.bind(('', MCAST_PORT))
表示如果 IS_ALL_GROUPS
为真,则将套接字绑定到任何地址,否则: socket_name.bind((MCAST_GRP, MCAST_PORT))
表示将套接字绑定到特定给定的 IP 地址。
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
表示将 IP 地址转换为二进制形式,socket_name.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
表示我们添加组成员,此行之后数据包开始到达。
但是有些事情我不明白。
为什么当我使用 IS_ALL_GROUPS = true
时 MCAST_GRP = '239.0.1.104'
程序可以启动并且当参数为 false 时,它没有绑定到特定的多播地址?我的逻辑是,当参数为真时,它绑定到他从 IGMP 加入消息中获得的任何 MCast 地址,当参数为假时,它绑定到特定的给定地址。我说得对吗?
我有一个分析比特率的多线程程序,我以列表的形式提供了多个地址。当我将 IS_ALL_GROUPS
设置为 false 时,程序可以正确打印出来,例如10.5, 4.5, 5.0
其中每个结果都是来自唯一地址的一个流的比特率,但是所有地址共享同一个端口 12345
。当我将 IS_ALL_GROUPS
设置为 true 时,程序汇总结果给出 20.0, 20.0, 20.0
,你知道可能是什么原因吗?
import socket
import struct
MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
IS_ALL_GROUPS = True
socket_name = 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
socket_name.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
socket_name.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 socket_name.recv(10240)
我认为有几件事正在发生:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
应该probably be:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
唯一基于 "datagram" 的 IPv4 协议是 UDP,协议字段仅用于 "raw sockets",它被 tcpdump
等程序使用。不过这不重要。
下一个:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
只允许多个套接字一次绑定到相同的 (addr, port)
组合,即您可以一次 运行 程序的多个副本,或快速连续。我想这就是你所说的
下一个:
sock.bind((host, port))
表示您想接收发往给定地址和端口的数据包。特殊地址 ''
(即 INADDR_ANY
)意味着内核不应该对地址进行任何过滤。您可能不想在此阶段绑定到任何特定地址,请参阅 What does it mean to bind a multicast (UDP) socket?
下一个:
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
我建议使用 "=4sl"
作为格式字符串,因为这给了我 8 个字节,而不是 16 个字节,并且与我 (Linux) 上的 C struct ip_mreq
一致系统。这种填充差异可能只是一个 32/64 位问题,而且似乎没有什么坏处
总结一下:1. setsockopt(IP_ADD_MEMBERSHIP)
调用要求您的内核网络堆栈安排(通过 IGMP)将发送到 MCAST_GRP
的多播数据包传送到连接到您主机的网络接口. 2. bind()
调用已安排通过网络接口接收到的数据包到达进程中的套接字。 bind()
指定 INADDR_ANY
可能很重要,这样所有到达的多播数据包都会传送到您的进程而不是被过滤
一些可能有用的命令行是:
tcpdump -i eth0 -vv 'ip proto 2'
转储 IGMP 数据包,并且:
tcpdump -i eth0 -vv 'net 224.0.0.0/4'
转储多播数据包
我不确定你的 "multithread analysis program" 在做什么,因为你没有提供任何相关信息。你发的代码也不对,大概socket_name
和sock
是一样的吧?我还建议使用 Python 3 因为 Python 2 快死了