【发布时间】:2023-03-07 11:22:01
【问题描述】:
我是龙卷风的初学者,通常是 websockets/networking。
我想要做的是在桌面窗口应用程序中实现一个 websocket 客户端,即:
- 从服务器接收一些随机数据,读取它,检查数据并 在外部向某些小部件发出信号
- 向服务器发送数据(服务器无响应)
(到目前为止,我设法做到了这一点)
- 在某些外部功能(如在小部件中)向服务器发送数据:
def request_masks_export(self, export_dir):
wrapped_command = {
"clientAction": "exportMasks",
"clientData": {
"client": "Remote Browser is requesting to export masks files.",
"exportDir": export_dir
}
}
response = self.current_connection_manager.send_sync(wrapped_command)
# response from send_sync here
...并等待它得到响应,然后在函数内继续。 我无法理解它来做这件事......
这是我的代码:
class ConnectionManager(QThread):
on_data = Signal(dict)
connection_interrupted = Signal()
_default_url = "ws://localhost:12345/"
_identifier = {
"clientAction": "newClientConnected",
"clientData": {
"client": "connected from python app: {}".format(os.path.basename(__file__))
}
}
def __init__(self, url=None, timeout=None, parent=None):
QThread.__init__(self, parent)
self.ioloop = IOLoop.current()
if url is not None:
self.url = url
else:
self.url = self._default_url
if timeout is not None:
self.timeout = timeout
else:
self.timeout = 1
self.ws_connection = None
@gen.coroutine
def connect_to_server(self):
try:
start_time = time.time()
self.ws_connection = yield websocket_connect(self.url)
self.ws_connection.connect_future.add_done_callback(self.connect_callback)
print 'Elapsed time of connection: %.1f msec' % (time.time() - start_time) * 1000
self.send(self._identifier)
except socket.error as e:
print e
if e.errno == errno.ECONNREFUSED:
print 'Connection has been refused. Awaiting connection...'
yield gen.sleep(self.timeout)
self.connect_to_server()
except Exception as e:
print "unable to connect websocket server"
print e
def run(self):
self.ioloop.spawn_callback(self.connect_to_server)
self.ioloop.start()
def connect_callback(self, future):
if future.exception() is None:
self.ws_connection = future.result()
self._on_connection_success()
self.read_message()
else:
self.on_connection_error(future.exception())
@gen.coroutine
def read_message(self):
# reading here all messages, except those that are result of def send_sync
while True:
msg = yield self.ws_connection.read_message()
if msg is None:
self.on_connection_close()
break
self.check_data(msg)
@gen.coroutine
def send(self, data):
if isinstance(data, dict):
json_object = json.dumps(data)
res = yield self.ws_connection.write_message(json_object)
# from here I just send messages that don't need response
@gen.coroutine
def send_sync(self, data):
if isinstance(data, dict):
json_object = json.dumps(data)
response = yield self.ws_connection.write_message(json_object)
# I want to get response messege from server here to be able to return it 'somehow'
def check_data(self, raw_msg):
"""
Callback function when message is received from server.
Emits signal
:param raw_msg: unicode message received from server
:return:
"""
try:
if raw_msg is None:
raise WebSocketNoneError("raw_msg received is None!", "none data")
try:
raw_data_dict = json.loads(raw_msg)
except ValueError as e:
# handles json decode error from raw_msg(string)
print e
raise WebSocketMessageError("Incompatible message type!", "JSON only")
if raw_data_dict.has_key("serverAction"):
self.on_data.emit(raw_data_dict)
return raw_data_dict
else:
raise WebSocketMessageError("Incompatible message structure!", "missing serverAction")
except WebSocketMessageError as e:
print e.args
raise
except WebSocketNoneError as e:
print e.args
raise
def close_manager(self):
"""
Method for stopping websocket, waiting for thread to finish and stop it.
:return:
"""
self.close_websocket()
self.ioloop.stop()
self.stop()
def is_connected(self):
if not self.ws_connection:
return False
else:
return True
def stop(self):
"""
Stop thread.
:return:
"""
self.quit()
self.wait()
def close_websocket(self):
"""
Close websocket.
:return:
"""
try:
self.ws_connection.close()
except Exception as e:
print e
pass
def on_connection_success(self):
print "_on_connection_success"
pass
def on_connection_close(self):
print "_on_connection_close"
self.connection_interrupted.emit()
self.connect_to_server()
pass
我正在使用:
class ConnectionManager(QThread):
因为它阻塞了用于应用程序其余部分的线程...这是正确的方法吗?如果我错了,请纠正我,但我不会在 QThread 中这样做,然后整个应用程序将加载到 iolopp.start() 点并且不会执行超过该元素,而是等待/监听传入的消息, ETC...
我也对龙卷风中的连接类型有点困惑。 websocket 连接的例子并不多,相反有很多关于 HTTP 的例子。由于所有这些东西对我来说都是新的,所以也许我误解了一些东西,但我认为只有初始握手是基于 websockets 的 http,我不能使用像 RequestHandler、tornado.httpclient 这样的类。
【问题讨论】:
-
我想 PyQT/QT 已经有某种事件循环甚至 websocket 库,你应该使用它们,而不是使用 Tornado 的事件循环和网络工具(你应该只留给你的后端) . Very shallow and fast search shows, that this is quite true.
-
是的,我明白这一点,但我想使用龙卷风而不是别的。我知道这是可以实现的,对于有经验的龙卷风用户来说可能相当容易。
标签: python-2.7 websocket client tornado