我开始进入WebSockets,以便将数据从服务器推送到连接的客户端。因为我使用python来编写任何类型的逻辑,所以我到目前为止看了Tornado。下面的代码段显示了在网络上随处可见的最基本的示例:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print 'new connection'
self.write_message("Hello World")
def on_message(self, message):
print 'message received %s' % message
self.write_message('ECHO: ' + message)
def on_close(self):
print 'connection closed'
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
实际上,这是按预期工作的。但是,我无法理解如何才能获得这个"集成"进入我的应用程序的其余部分。在上面的示例中,WebSocket仅向客户端发送内容作为对客户端消息的回复。如何从"外部"?访问WebSocket?例如,要通知所有当前连接的客户端已发生某种事件 - 此事件不是来自客户端的任何类型的消息。理想情况下,我想在我的代码中的某处写一下:
websocket_server.send_to_all_clients("Good news everyone...")
我该怎么做?或者我对WebSockets(或Tornado)应该如何工作有一个完全的误解。谢谢!
答案 0 :(得分:10)
您需要跟踪所有连接的客户端。所以:
clients = []
def send_to_all_clients(message):
for client in clients:
client.write_message(message)
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
send_to_all_clients("new client")
clients.append(self)
def on_close(self):
clients.remove(self)
send_to_all_clients("removing client")
def on_message(self, message):
for client in clients:
if client != self:
client.write_message('ECHO: ' + message)
答案 1 :(得分:10)
这是以Hans Then的例子为基础的。希望它可以帮助您了解如何让服务器与客户进行通信,而客户不会触发交互。
这是服务器:
#!/usr/bin/python
import datetime
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def open(self):
print 'new connection'
self.write_message("Hello World")
WSHandler.clients.append(self)
def on_message(self, message):
print 'message received %s' % message
self.write_message('ECHO: ' + message)
def on_close(self):
print 'connection closed'
WSHandler.clients.remove(self)
@classmethod
def write_to_clients(cls):
print "Writing to clients"
for client in cls.clients:
client.write_message("Hi there!")
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().add_timeout(datetime.timedelta(seconds=15), WSHandler.write_to_clients)
tornado.ioloop.IOLoop.instance().start()
我将客户端列表设为类变量,而不是全局变量。我实际上不介意使用全局变量,但是因为你关心它,所以这是另一种方法。
这是一个示例客户端:
#!/usr/bin/python
import tornado.websocket
from tornado import gen
@gen.coroutine
def test_ws():
client = yield tornado.websocket.websocket_connect("ws://localhost:8888/ws")
client.write_message("Testing from client")
msg = yield client.read_message()
print("msg is %s" % msg)
msg = yield client.read_message()
print("msg is %s" % msg)
msg = yield client.read_message()
print("msg is %s" % msg)
client.close()
if __name__ == "__main__":
tornado.ioloop.IOLoop.instance().run_sync(test_ws)
然后,您可以运行服务器,并有两个测试客户端连接实例。执行此操作时,服务器将打印出:
bennu@daveadmin:~$ ./torn.py
new connection
message received Testing from client
new connection
message received Testing from client
<15 second delay>
Writing to clients
connection closed
connection closed
第一个客户打印出来:
bennu@daveadmin:~$ ./web_client.py
msg is Hello World
msg is ECHO: Testing from client
< 15 second delay>
msg is Hi there! 0
第二个打印出来:
bennu@daveadmin:~$ ./web_client.py
msg is Hello World
msg is ECHO: Testing from client
< 15 second delay>
msg is Hi there! 1
出于示例的目的,我让服务器在15秒的延迟时间内将消息发送给客户端,但它可以由您想要的任何内容触发。
答案 2 :(得分:0)
我的解决方案:首先将"if __name__ == '__main__':"
添加到main.py.然后将main.py导入websocket模块。例如(import main as MainApp
)。现在可以在&#39; main.py&#39;中调用函数。来自ws.py/WebSocketHandler-function。 - 在Handler内部传递消息,如下所示:
MainApp.function(message)
我不知道如果这是优雅的反面但它对我有用。
..另外创建并导入自定义&#39; config.py&#39; (那似乎是:someVar = int(0)
)进入&#39; mainApp.py&#39; ..像这样:import config as cfg
- &gt;现在,您可以在&main;主要内容中使用cfg.someVar = newValue
更改变量。那个曾经被处理程序从&#39; ws.py&#39;。