我是龙卷风的初学者,通常是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()并且不会执行该元素,而是等待/收听传入的消息等...
我也对龙卷风中的连接类型感到困惑。没有很多websocket连接的例子,而是有很多关于HTTP的例子。因为所有这些对我来说都是新的,所以也许我误解了一些事情,但我认为只有初始握手是基于http的http来基于websockets我不能使用像RequestHandler
,tornado.httpclient
这样的类
答案 0 :(得分:0)
我不知道如何以收益的方式做到这一点,但我可以看到一个非常简单的回调方式解决方案,如果你对它好的话。您可以通过Tornado的事件循环和QT事件循环之间的交互来实现这一点。我不知道PyQT,所以我会展示一些抽象概念,而不是工作代码。
def request_masks_export(self, export_dir):
# ...
IOLoop.current().add_callback(send_sync,
wrapped_command,
some_func_to_call_after_request_is_finished)
@gen.coroutine
def send_sync(self, data, callback_func):
if isinstance(data, dict):
json_object = json.dumps(data)
response = yield self.ws_connection.write_message(json_object)
QTEventLoop.add_callback(callback_func, response)