个人感觉tornado的websocket要比flask-socketio要好得多,毕竟tornado是原生支持,flask-socketio要依靠gevent或者eventlet,这两个库当中貌似有不少的坑
个人感觉python的socketio服务器一般有两种比较典型的选择,flask-socketio+socket.io-client和tornado.websocket+原生websocket,这两者之前我最近做了一个比较
接受消息
flask-socketio收到前端的消息后会启动定义的event handler,然而在这个event handler中发送的消息要等这个event handler全部执行完毕以后才会发送,而且执行过程中无法响应心跳包。这就导致,当单个event handler执行耗时操作时,会一直没有任何消息发送到前端,如果时间太长前端会判断为超时,然后发起重连请求,真的很糟心。以下是示例,后台收到testmessage的事件后,每隔10秒发送一个消息到前台,然而事实情况会是一个包都没有发送到前端,前端就判断为超时了。
后台代码
前端
像以上的代码,前端会一个信息都收不到,因为后台处理耗时太久,前端认为断开了。并且浏览器控制台会出现如下错误,貌似是socketio延时后回退到使用ajax,然后禁止跨域了?
由于我的业务是遍历一个过滤一个列表,比较耗时,一开始对整个列表的过滤写在一个socket.on里面,还以为是有延迟,后面的消息和前面的消息冲突了,没有收到,实际是后台一直无法响应心跳包导致前端认为超时了。这篇文章中的异步切换方案完全是完全没有用的,无论是socketio.sleep(10)
还是time.sleep(10)
都是没有用的,只会徒增响应时间,使问题加剧。
此issue和这个问题就是在讨论这个问题。作者给出的建议是尽量使用较短的event handlers,实在不行的话就使用eventlet或gevent线程处理任务。
至于tornado则完全没有缓冲区的问题,发送信息的函数执行后前端会立即收到信息。以下是实例代码。
前端
python控制台输出message sent!后前端会立即弹出收到消息,没有缓存的问题。我试过把睡眠时间增加到100秒也是完全没问题的。
超时时间
这篇文章是阐述地比较清楚的。
socketio系列的优点
首先当然是可以兼容相当多的浏览器,第二是可以支持emit(event, message)这样指定事件名的发送和响应,而原生websocket只能使用简单的send(message)。如果你需要自定义很多不同类型的消息那么无疑从socketio转移到原生的websocket是十分困难的,通过手动判断数据内容会很消耗性能而且很麻烦,如果通过uri区分不同类型数据,一方面来说管理多个websocket连接是比较麻烦的,另一方面tornado是会给不同的uri添加不同的handler类,handler类的生命周期在client为关闭浏览器之前,换句话说,某一个websocket请求改变了这个handler实例的属性值,在另一个(针对相同URi的)websocket连接中是可以访问这个属性的,在发起开始/停止命令的时候是比较有用的。但跨URI就不行了毕竟不是一个类,不知道设置全局变量可不可行。