0%

Python接收UDP组播

UDP 全称 User Datagram Protocol( 用户数据报协议 ),是 Internet 的传输层两个主要协议之一,相对于另外一个协议TCP而言,UDP是一种无需建立连接就可以发送封装的 IP 数据包的方法,但不是完全可靠的,丢包什么的都不管,在牺牲一定传输完整性保障的基础上,保证了传输性能;

UDP 组播是其发送数据的方法之一,特点就是发送端可以将消息发送到特定播组内,接收端只要处于该播组就可以接收到该消息;

那么用Python编程时,应该怎么接入UDP的组播呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import socket
import struct
import requests

multi_cast_group = '233.255.255.100' # 播组
server_address = ('', 6001) # 播组端口

# Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 告诉socket是UDP
sock.setblocking(False) # 这里主要目的是防止拥塞的,后面会简要说明
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# Bind to the server address
sock.bind(server_address)

# Tell the operating system to add the socket to the multi_cast group on all interfaces.
group = socket.inet_aton(multi_cast_group)
m_req = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, m_req)

# Receive/respond loop
while True:
try:
data, address = sock.recvfrom(65535) # socket的recvfrom()会返回数据以及相应的地址
print('received {} bytes from {}'.format(len(data), address))
except BlockingIOError:
# 因为某些特殊原因,这里略去了先判断时间的过程,源码里是做了一个判断:
# 如果24小时内未收到消息,则执行下面的语句
print('温馨提示: 24小时内未收到消息,请知悉并确认')

上述代码结合注释应该比较清楚了,另外有几点简单说明一下:

  1. 关于 setblocking 为false,其实是为了满足后面的另外一个需求:如果一定时间段内(比如24小时内)一直收不到UDP组播消息,也需要在微信或者钉钉提示一下,也是为了确认到底是没有UDP组播消息,还是该推送程序本身除了问题。
  2. 在实际测试中发现,在最后的while True循环中,如果不设置setblocking为false,那么就会发生拥塞,即 data, address = sock.recvfrom(65535) 这一语句持续执行,后面的语句无法执行。
  3. 解决办法就是用try,同时捕捉 BlockingIOError ,这样就可以在接收不到消息的时候执行其它操作了。

以上基本就是Python编程接收UDP组播消息的方法,由于一些特殊原因,中间略去了部分内容,可能会一定程度上影响阅读,还望见谅。

有相关问题欢迎在评论区留言讨论,本人也是菜鸟,有说的不对的,还请大佬们多指教。