Tornado长轮询和WebSocket
Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息.
短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应.
短轮询存在严重缺陷:
-
短轮询需要进行高频率的网络通信, 且收到大多数轮询请求时服务端没有消息需要推送.
-
需要维护大量Http连接, 严重消耗资源
如果手写一个短轮询的话你会发现, 短轮询带来的问题不止这些.
长轮询#
长轮询是客户端向服务端发送一个刷新请求, 并保持连接打开. 服务端收到请求后不立即响应,等到需要推送消息时再返回. 然后, 客户端再次发送刷新请求并等待推送.
长轮询不再需要频繁发送刷新请求, 但是长期等待的Http连接可能断开, 需要考虑异常处理.
长轮询请求等待过程中服务端处理进程不能被阻塞, tornado的异步IO机制可以方便的使用长轮询.
import tornado.httpserver
from tornado.ioloop import IOLoop
import tornado.options
import json
from tornado.web import Application, RequestHandler, asynchronous
class ChatApp(Application):
def __init__(self):
handlers = [
(r'/new-message', NewMsgHandler),
(r'/update-message', UpdateMsgHandler)
]
super(ChatApp, self).__init__(self, handlers=handlers)
self.cache = []
class NewMsgHandler(RequestHandler):
def __init__(self, app):
self.app = app
def post(self):
msg = self.get_argument('msg')
self.app.cache.append(msg)
class UpdateMsgHandler(RequestHandler):
def __init__(self, app):
self.app = app
@asynchronous
def post(self):
if self.request.connection.stream.closed():
return
response_json = json.dumps(self.app.cache)
self.write(response_json)
self.finish()
def main():
tornado.options.parse_command_line()
app = ChatApp()
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if __name__ == '__main__':
main()
示例的完整代码,请去草民的仓库
这篇博客提供了一个更为强大的基于长轮询的聊天室, 而且草民非常喜欢他的代码风格.
长连接断开的处理机制可以参考这篇文章
WebSocket#
WebSocket是HTML5协议中提出的客户-服务器通信协议, 它允许双方以类似TcpSocket的方式进行通信.
它基于标准Http协议实现, 但使用新的ws://URL格式.
Tornado在websocket模块中提供了一个WebSocketHandler类,
-
open方法在一个新的WebSocket连接打开时被调用,
-
on_message方法在连接接收到新的消息时被调用
-
on_close方法在客户端关闭时被调用
-
write_message(message, binary=False)方法可以通过WebSocket向对方发送数据
- 若binary=False, message可以是string或者dict(会被自动编码为JSON), - 若binary=True, message可以是任意byte string
继承WebSocketHandler并重写自己上述方法,实现基于WebSocket的应用.
来自tornado官方文档的示例:
class EchoHandler(WebSocketHandler):
def allow_draft76(self):
return True
def check_origin(self, origin):
return True
def open(self):
print "new client opened"
def on_close(self):
print "client closed"
def on_message(self, message):
self.write_message(message)
allow_draft76
与check_origin
用于进行安全性校验, 只有它们都返回True时WebSocket才能正常连接.
Python WebSocket#
WebSocket虽然是为Web应用设计的, 为了减轻后端的开发压力可以采用WenSocket代替Tcp Socket与后端交互.
Websocket-client是Python Websocket支持包,可以使用pip安装:
pip install websocket-client
websocket-client提供了几个低级API:
- 建立websocket连接
ws = create_connection("ws://echo.websocket.org/")
- 发送消息
ws.send(msg)
- 接收消息
result = ws.recv()
- 关闭连接
ws.close()
websocket也提供了JS风格的API, 来自官方文档的示例:
import websocket
import thread
import time
def on_message(ws, message):
print message
def on_error(ws, error):
print error
def on_close(ws):
print "### closed ###"
def on_open(ws):
def run(*args):
for i in range(3):
time.sleep(1)
ws.send("Hello %d" % i)
time.sleep(1)
ws.close()
print "thread terminating..."
thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp(
"ws://echo.websocket.org/",
on_message = on_message,
on_error = on_error,
on_close = on_close
)
ws.on_open = on_open
ws.run_forever()
更多信息请参见Github websocket-client
作者:finley
出处:https://www.cnblogs.com/Finley/p/5517769.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!