python - udp 端口在所有进程中被阻止(python - pi)
问题描述
我在自制安全系统中有一个 Raspberry PI 控制器网络。每一个都为不同的功能启动几个独立的进程,一个 MQTT 代理将所有东西联系在一起。
每个 PI/进程都使用 MQTT 代理的地址进行硬编码,我希望每个 PI/进程都向中央服务器查询代理的位置。
我让每个进程都打开一个用于广播的 UDP 套接字集,并且每个进程都绑定到不同的侦听端口。启动时,它向中央服务器发送一个查询(包括其侦听端口),中央服务器将回复发送到正确的侦听端口。
这仅适用于一个进程,其他进程(在同一个 PI 上)都超时而没有得到响应。Wireshark 显示只有三个中的一个实际上将查询发送到 Wire,奇怪的是打开套接字的最后一个进程是有效的。调试日志中的片段:
mpi@RPI02:~ $ cat /var/log/vlab.debug.log
2020-02-28 17:08:55,242 garagectlr.31: startup
2020-02-28 17:08:55,243 root.2:
2020-02-28 17:08:55,244 root.2: startup
2020-02-28 17:08:55,250 root: looking for broker on port 10417...
2020-02-28 17:08:55,255 garagectlr: looking for broker on port 10416...
2020-02-28 17:08:57,117 sms-receiver.18:
2020-02-28 17:08:57,118 sms-receiver.18: startup
2020-02-28 17:08:57,121 sms-receiver: looking for broker on port 10419...
2020-02-28 17:08:57,124 sms-receiver: rx [mqtt-broker=192.168.99.99]
2020-02-28 17:08:57,225 sms-receiver: located broker at 192.168.99.99
2020-02-28 17:08:57,255 root: FATAL: unable to locate MQTT broker
2020-02-28 17:08:57,260 garagectlr: FATAL: unable to locate MQTT broker
2020-02-28 17:08:57,270 * Running on http://192.168.99.162:6060/ (Press CTRL+C to quit)
这是每个 PI 的相关 python 代码,剪掉了一点:
#
# start looking for broker
#
# get unique listening port
listen_port = os.getpid() + 10000
logging.debug("%s: looking for broker on port %d..."%(self.process,listen_port))
try:
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(('',listen_port))
except Exception:
logging.exception("%s: "%(self.process))
tries = 0
try:
while self.broker == None and tries < 2:
query = "query mqtt-broker:%s:%d"%(self.process,listen_port)
sock.sendto(query,("192.168.99.255",1414))
sock.settimeout(2)
data,addr = sock.recvfrom(64)
logging.debug("%s: rx [%s]"%(self.process,data))
if data[0:5]=='mqtt-':
self.broker = data[12:]
time.sleep(.1)
else:
time.sleep(1)
tries = tries + 1
except Exception:
print('timeout')
sock.close()
if self.broker == None:
logging.debug("%s: FATAL: unable to locate MQTT broker"%(self.process))
else:
logging.debug("%s: located broker at %s"%(self.process,self.broker))
self.sendBoot()
self.pubTest("mqtt@%s.%s startup"%(self.process,self.version))
m_thread = threading.Thread(target = self.mqtt_thread)
m_thread.start()
我认为,通过绑定到 RX 的唯一端口,我不会在套接字之间产生任何干扰,但显然只有一个在工作。为什么另外两个甚至不发送查询?
解决方案
我注意到我在 TRY-CATCH 块中有 WHILE 循环,所以当接收器第一次超时时,while 循环被破坏了。
我将 TRY 放在 WHILE 中,如下所示:
tries = 0
query = "query mqtt-broker:%s:%d"%(self.process,listen_port)
while self.broker == None and tries < 4:
try:
sock.sendto(query,("192.168.99.255",1414))
sock.settimeout(2)
data,addr = sock.recvfrom(64)
if data[0:5]=='mqtt-':
self.broker = data[12:]
time.sleep(.1)
else:
time.sleep(1)
tries = tries + 1
except Exception:
pass ## timeout
try:
sock.close()
except Exception:
logging.exception("%s: "%(self.process))
认为如果查询失败,每个进程都有机会重试。我不确定首先出了什么问题,但是现在这很可靠:
mpi@RPI02:~ $ cat /var/log/vlab.debug.log
2020-02-29 17:07:47,981 root.2:
2020-02-29 17:07:47,982 root.2: startup
2020-02-29 17:07:47,986 garagectlr.31: startup
2020-02-29 17:07:47,992 garagectlr: looking for broker on port 10421...
2020-02-29 17:07:48,010 root: looking for broker on port 10424...
2020-02-29 17:07:49,895 sms-receiver.18:
2020-02-29 17:07:49,896 sms-receiver.18: startup
2020-02-29 17:07:49,901 sms-receiver: looking for broker on port 10423...
2020-02-29 17:07:50,004 sms-receiver: located broker at 192.168.99.99
2020-02-29 17:07:50,048 sms-receiver: * Running on http://192.168.99.162:6060
2020-02-29 17:07:50,098 garagectlr: located broker at 192.168.99.99
2020-02-29 17:07:50,140 root: located broker at 192.168.99.99
mpi@RPI02:~ $
我认为奇怪的是查询被堆叠,然后以相反的顺序得到满足。但是,嘿,它有效。