11.2.5 组播
点对点连接可以处理很多通信需求,不过随着直接连接数的增加,在多对通信方之间传递相同的消息会变得越来越困难。单独地向各个接收方发送消息会耗费额外的处理时间和带宽,这对于诸如完成流视频或音频操作的应用来说会带来问题。使用组播(multicast)向多个端点同时发送消息可以得到更好的效率,因为网络基础设施可以确保数据包会被传送到所有接收方。组播消息总是使用UDP发送,因为TCP需要提供一对通信系统。组播的地址被称为组播组(multicast group),这是常规的IPv4地址范围的一个子集(224.0.0.0~230.255.255.255),专门为组播通信预留。这些地址会由网络路由器和交换机进行特殊处理,所以发送到组的消息可以在互联网上被分发到加入这个组的所有接收方。
说明:一些托管交换机和路由器默认地会禁用组播通信。如果运行这些示例程序有问题,那么可以检查你的网络设置。
11.2.5.1 发送组播消息
下一个例子中修改后的回送客户会向一个组播组发送一个消息,然后报告它收到的所有响应。由于无法知道会收到多少响应。所以它对套接字使用了一个超时值,以避免等待回答时无限阻塞。配置这个套接字时还需要提供消息的一个生存时间值(Time-To-Live value,TTL)。TTL会控制多少网络接收这个数据包。要使用IP_MULTICAST_TTL选项和setsockopt()来设置TTL。默认值1表示路由器不会把数据包转发到当前网段之外。TTL的取值范围最大为255,应包装为一个字节。
import socket
import struct
import sys
message = b'very important data'
multicast_group = ('224.3.29.71',10000)
# Create the datagram socket.
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# Set a timeout so the socket does not block
# indefinitely when trying to receive data.
sock.settimeout(0.2)
# Set the time-to-live for message to 1 so they do not
# go past the local network segment.
ttl = struct.pack('b',1)
sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,ttl)
try:
# Send data to the multicast group.
print('sending {!r}'.format(message))
sent = sock.sendto(message,multicast_group)
# Look for responses from all recipients.
while True:
print('waiting to receive')
try:
data,server = sock.recvfrom(16)
except socket.timeout:
print('time out, no more responses')
break
else:
print('received {!r} from {}'.format(
data,server))
finally:
print('closing socket')
sock.close()
发送者程序的其余代码似于UDP回送客户,只是它可能会接收多个响应,所以这里使用一个循环来调用recvfrom(),直到超时。