Python 为什么flask_socketio.disconnect会阻止线程完成?
我有以下系统:[Client]-[Web服务器]-[connectr] 连接器是web服务器和数据源之间的一种中间代码 我需要监视服务器与连接器的连接。如果连接丢失,那么我必须通知客户端 web服务器和连接器之间的通信是使用socketio组织的 问题是,如果连接器停止工作,web服务器只会在一分钟后知道它(这是最好的情况) 我决定服务器应该每秒检查连接器的状态 当连接器连接到服务器上时,后台任务启动。任务的实质是:每秒钟:1)确定时间;2) 将固定时间保存到堆栈中;3) 将回显消息发送到连接器。(请参阅server.background\u线程) 连接器接受回显消息和时间戳作为参数,并将回显消息发送到web服务器,作为它传递接收到的时间戳的参数。(参见client.echo) web服务器接收回显消息,如果时间戳等于堆栈中的最后一个值,则该值将从堆栈中删除。(请参阅服务器上的echo连接器) 在web服务器上,每次迭代都会检查堆栈大小(请参阅server.background\u thread)。如果大于5,则这意味着连接器未响应回显消息5次,我们认为连接器不可用,并将其断开 当服务器意识到连接器不可用时,有必要终止向连接器发送回显消息的线程 一旦堆栈大小大于5,我就退出无限循环并调用Python 为什么flask_socketio.disconnect会阻止线程完成?,python,flask-socketio,gevent-socketio,python-socketio,Python,Flask Socketio,Gevent Socketio,Python Socketio,我有以下系统:[Client]-[Web服务器]-[connectr] 连接器是web服务器和数据源之间的一种中间代码 我需要监视服务器与连接器的连接。如果连接丢失,那么我必须通知客户端 web服务器和连接器之间的通信是使用socketio组织的 问题是,如果连接器停止工作,web服务器只会在一分钟后知道它(这是最好的情况) 我决定服务器应该每秒检查连接器的状态 当连接器连接到服务器上时,后台任务启动。任务的实质是:每秒钟:1)确定时间;2) 将固定时间保存到堆栈中;3) 将回显消息发送到连接器
flask\u socketio.disconnect(connector\u sid,“/connector”)
。在此调用之后,一切都不起作用(例如,打印
)
在断开连接器(服务器)方法上的中,调用了thread.join()
,并且从不终止
我需要完成线程,这样当连接器再次启动时,它将成功连接,一切都将重新启动
如何解决这个问题
服务器
# -*- coding: utf-8 -*-
import os
import threading
import time
import collections
from datetime import datetime
import flask
import flask_socketio
def get_unix_time():
return int(time.mktime(datetime.now().timetuple()))
class Stack(collections.deque):
def __init__(self, iterable=(), maxlen=None):
collections.deque.__init__(self, iterable, maxlen)
@property
def size(self):
return len(self)
@property
def empty(self):
return self.size == 0
@property
def head(self):
return self[-1]
@property
def tail(self):
return self[0]
def push(self, x):
self.append(x)
# SERVER
app = flask.Flask(__name__)
sio = flask_socketio.SocketIO(app, async_mode='gevent')
connector_sid = None
echo_stack = Stack()
thread = None
thread_lock = threading.Lock()
def background_thread(app):
time.sleep(2) # delay for normal connection
while True:
if echo_stack.size >= 5:
break
time_ = get_unix_time()
echo_stack.push(time_)
sio.emit('echo', time_, namespace='/connector')
sio.sleep(1)
with app.app_context():
flask_socketio.disconnect(connector_sid, '/connector')
@sio.on('connect', namespace='/connector')
def on_connect_connector():
"""Connector connection event handler."""
global connector_sid, thread
print 'Attempt to connect a connector {}...'.format(request.sid)
# if the connector is already connected, reject the connection
if connector_sid is not None:
print 'Connection for connector {} rejected'.format(request.sid)
return False
# raise flask_socketio.ConnectionRefusedError('Connector already connected')
connector_sid = request.sid
print('Connector {} connected'.format(request.sid))
with thread_lock:
if thread is None:
thread = sio.start_background_task(
background_thread, current_app._get_current_object())
# notify clients about connecting a connector
sio.emit('set_connector_status', True, namespace='/client')
@sio.on('disconnect', namespace='/connector')
def on_disconnect_connector():
"""Connector disconnect event handler."""
global connector_sid, thread
print 'start join'
thread.join()
print 'end join'
thread = None
print 'after disconet:', thread
connector_sid = None
echo_stack.clear()
print('Connector {} disconnect'.format(request.sid))
# notify clients of disconnected connector
sio.emit('set_connector_status', False, namespace='/client')
@sio.on('echo', namespace='/connector')
def on_echo_connector(time_):
if not echo_stack.empty:
if echo_stack.head == time_:
echo_stack.pop()
@sio.on('message', namespace='/connector')
def on_message_connector(cnt):
# print 'Msg: {}'.format(cnt)
pass
if __name__ == '__main__':
sio.run(app)
客户
# -*- coding: utf-8 -*-
import sys
import threading
import time
import socketio
import socketio.exceptions
sio = socketio.Client()
thread = None
thread_lock = threading.Lock()
work = False
def background_thread():
# example task
cnt = 0
while work:
cnt += 1
if cnt % 10 == 0:
sio.emit('message', cnt // 10, namespace='/connector')
sio.sleep(0.1)
@sio.on('connect', namespace='/connector')
def on_connect():
"""Server connection event handler."""
global thread, work
print '\n----- Connected to server -----' \
'\n----- My SID: {} -----\n'.format(sio.sid)
work = True # set flag
# run test task
with thread_lock:
if thread is None:
thread = sio.start_background_task(background_thread)
@sio.on('disconnect', namespace='/connector')
def on_disconnect():
"""Server disconnect event handler."""
global thread, work
# clear the work flag so that at the next iteration the endless loop ends
work = False
thread.join()
thread = None
# disconnect from server
sio.disconnect()
print '\n----- Disconnected from server -----\n'
# switch to the mode of infinite attempts to connect to the server
main()
@sio.on('echo', namespace='/connector')
def on_echo(time_):
sio.emit('echo', time_, namespace='/connector')
def main():
while True:
try:
sio.connect('http://localhost:5000/connector',
namespaces=['/connector'])
sio.wait()
except socketio.exceptions.ConnectionError:
print 'Trying to connect to the server...'
time.sleep(1)
except KeyboardInterrupt:
print '\n---------- EXIT ---------\n'
sys.exit()
except Exception as e:
print e
if __name__ == '__main__':
print '\n---------- START CLIENT ----------\n'
main()
Python 2.7需要为客户端安装一个附加库()
多亏了这个库,WebSocket传输工作正常。现在可以立即看到断开接头。为什么需要一分钟才能检测到断开?这仅适用于HTTP连接,但当连接位于WebSocket上时,会立即检测到断开连接。您是否验证了您的客户端是否通过WebSocket连接?@Miguel,否,您是否在谈论客户端的“连接传输”?@Miguel,连接传输==无。我将客户端连接更新为sio.connect('http://localhost:5000/connector',名称空间=['/connector'],传输=['websocket'])。但是现在客户端甚至连服务器都没有连接。每次连接后,“sio.connected==True”,但服务器看不到客户端,客户端在循环中无休止地连接。不,我想问的是,您的服务器是否支持通过WebSocket进行连接。要使其正常工作,您需要使用eventlet或gevent web服务器,如果您使用Flask web服务器,则不支持WebSocket。@Miguel,是的,我已经安装了gevent和gevent WebSocket软件包。问题是客户端没有切换到websocket传输。我找到了解决这个问题的办法。谢谢
pip install "python-socketio[client]"