Chr*_*ian 6 python webserver tornado websocket
我开始将WebSockets作为将数据从服务器推送到连接客户端的方式.因为我使用python来编写任何类型的逻辑,所以我到目前为止看了Tornado.下面的代码段显示了可以在Web上随处找到的最基本的示例:
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()
Run Code Online (Sandbox Code Playgroud)
实际上,这是按预期工作的.但是,我无法理解如何将这个"集成"到我的应用程序的其余部分.在上面的示例中,WebSocket仅向客户端发送内容作为对客户端消息的回复.如何从"外部"访问WebSocket?例如,要通知所有当前连接的客户端已发生某种事件 - 此事件不是来自客户端的任何类型的消息.理想情况下,我想在我的代码中的某处写一些类似于:
websocket_server.send_to_all_clients("Good news everyone...")
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?或者我对WebSockets(或Tornado)应该如何工作有一个完全的误解.谢谢!
Han*_*hen 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)
Run Code Online (Sandbox Code Playgroud)
dan*_*ano 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()
Run Code Online (Sandbox Code Playgroud)
我使客户端列表成为一个类变量,而不是全局变量.我实际上不介意为此使用全局变量,但是既然你关心它,这里是另一种方法.
这是一个示例客户端:
#!/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)
Run Code Online (Sandbox Code Playgroud)
然后,您可以运行服务器,并让测试客户端的两个实例连接.当你这样做时,服务器打印出这个:
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
Run Code Online (Sandbox Code Playgroud)
第一个客户打印这个:
bennu@daveadmin:~$ ./web_client.py
msg is Hello World
msg is ECHO: Testing from client
< 15 second delay>
msg is Hi there! 0
Run Code Online (Sandbox Code Playgroud)
第二个打印出来:
bennu@daveadmin:~$ ./web_client.py
msg is Hello World
msg is ECHO: Testing from client
< 15 second delay>
msg is Hi there! 1
Run Code Online (Sandbox Code Playgroud)
出于示例的目的,我只是让服务器在15秒的延迟时间内将消息发送给客户端,但它可以由您想要的任何内容触发.