tornado长轮询
1.什么是长轮询
顾名思义,长轮询就是不停循环请求服务器,获取最新信息。
长轮询分为两类:
1)浏览器以固定时间间隔向服务器发送请求
缺点是轮询频率要足够快,但又不能太频繁,否则当成百上千个客户端不断请求,会使web服务器面临极大压力
2)服务器推送
浏览器和服务器之间保持请求的连接,当服务器数据更新时,向浏览器响应新数据,然后关闭连接,浏览器接收到响应,重新发送请求,服务器保持请求状态,如此循环。
优点是极大减少了web服务器的负载,即时响应,用户体验佳。相对于方法1,客户端制造大量的短而频繁的请求(以及每次处理http头部产生的开销),服务器只有当其接受一个初始请求和再次发送响应时处理连接,大部分时间没有新的数据,连接也不会消耗任何处理器资源。
2.长轮询使用示例
以下示例中,用户可添加P商品(数量为10个)到购物车,当用户添加商品到购物车,或删除购物车的时候,其他用户可以适时看到P商品数量的变化。
1)用户访问主页
显示库存数量,添加/删除购物车操作
class DetailHandler(tornado.web.RequestHandler):
def get(self):
self.post()
def post(self):
#商品条码
session=uuid.uuid1()
#查询现有库存
count=self.application.shoppingCart.getInventoryCount()
#显示
self.render("index.html",session=session,count=count)
界面如下:
2)主页长轮询商品当前库存
class StatusHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
#注册添加/删除购物车后的回调函数
self.application.shoppingCart.register(self.on_message)
def on_message(self,count):
print str(count)
self.write('{"inventorycount":"%s"}'%count)
self.finish()
@tornado.web.asynchronous装饰器表示请求为异步IO类型,服务端没有主动调用finish()方法时,请求连接会一直保持。
register方法注册了在用户添加/删除购物车后,需要调用的回调函数
在用户添加/删除购物车后,服务器会调用所有连接中的请求注册的回调函数,将库存数量响应给所有连接请求,然后关闭每个连接,请求结束。
此时,客户端会循环发起请求,建立连接,当库存变化时,服务器推送新的数据到客户端,结束连接。如此循环
3)添加/删除购物车操作
class CartHandler(tornado.web.RequestHandler):
def get(self):
self.post()
def post(self):
action=self.get_argument('action')
session=self.get_argument('session')
if not session:
self.set_status(400)
return
if action=='add':
#添加到购物车
self.application.shoppingCart.moveItemToCart(session)
elif action=='remove':
#删除购物车
self.application.shoppingCart.removeItemFromCart(session)
else:
self.set_status(400)
4)具体看一看添加和删除操作系统处理流程
class ShoppingCart(object):
totalInventory=10
callbacks=[]
carts={} def register(self,callback):
self.callbacks.append(callback) def moveItemToCart(self,session):
if session in self.carts:
return
self.carts[session]=True
self.notifyCallbacks() def removeItemFromCart(self,session):
if session not in self.carts:
return
del(self.carts[session])
self.notifyCallbacks() def notifyCallbacks(self):
for c in self.callbacks:
print "**********"
self.callbackHelper(c)
self.callbacks=[] def callbackHelper(self,callback):
callback(self.getInventoryCount()) def getInventoryCount(self):
return self.totalInventory-len(self.carts)
moveItemToCart方法,添加操作时,将商品唯一标识码放入json串,然后将新库存作为参数,调用所有请求的回调,响应各个请求,并关闭连接。
removeItemFromCart方法,删除操作时,将商品唯一标识码清除,同样调用各回调,通知客户端。
5)客户端长轮询代码如下
$(document).ready(function() {
document.session = $('#session').val();
setTimeout(requestInventory, 100);
$('#add-button').click(function(event) {
jQuery.ajax({
url: 'http://localhost:9999/cart',
type: 'POST',
data: {
session: document.session,
action: 'add'
},
dataType: 'json',
beforeSend: function(xhr, settings) {
$(event.target).attr('disabled', 'disabled');
},
success: function(data, status, xhr) {
$('#add-to-cart').hide();
$('#remove-from-cart').show();
$(event.target).removeAttr('disabled');
}
});
});
$('#remove-button').click(function(event) {
jQuery.ajax({
url: 'http://localhost:9999/cart',
type: 'POST',
data: {
session: document.session,
action: 'remove'
},
dataType: 'json',
beforeSend: function(xhr, settings) {
$(event.target).attr('disabled', 'disabled');
},
success: function(data, status, xhr) {
$('#remove-from-cart').hide();
$('#add-to-cart').show();
$(event.target).removeAttr('disabled');
}
});
});
});
function requestInventory() {
jQuery.getJSON('http://localhost/status', {session: document.session},
function(data, status, xhr) {
$('#count').html(data.inventorycount);
setTimeout(requestInventory, 0);
}
);
}
6)运行结果
打开多个客户端,当做添加/删除操作时,可以观察到库存数量会实时变动。
3.长轮询的缺陷
上面有提到过长轮询的优势,经过上面的示例,我们可以明白长轮询存在的一些缺陷。
1)所有客户端请求同时关闭,同时打开,在库存变化的时候,服务器会受到猛烈的攻击
2)长轮询保持了连接请求,很多浏览器限制了对于服务器的并发请求数量,所以一直占用连接,会导致其他的请求如下载受到限制。
3)浏览器请求超时是由浏览器控制的。
参考资料:http://docs.pythontab.com/tornado/introduction-to-tornado/ch5.html
tornado长轮询的更多相关文章
- Tornado长轮询和WebSocket
Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息. 短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应. ...
- tornado 10 长轮询和 websocket
tornado 10 长轮询和 websocket 一.长轮询 #在网页,我们经常扫码登录,那么问题来了,前端是如何知道用户在手机上扫码登录的呢 这里就需要用到长轮询 #长轮询 #客户端能够不断地向服 ...
- http长轮询&短轮询
http 协议介绍: http 协议是请求/响应范式的, 每一个 http 响应都是由一个对应的 http 请求产生的; http 协议是无状态的, 多个 http 请求之间是没有关系的. http ...
- 三周,用长轮询实现Chat并迁移到Azure测试
公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都花在这上面了.简单地说就是用MVC4基于长 ...
- 用.NET MVC实现长轮询,与jQuery.AJAX即时双向通信
两周前用长轮询做了一个Chat,并移植到了Azure,还写了篇博客http://www.cnblogs.com/indream/p/3187540.html,让大家帮忙测试. 首先感谢300位注册用户 ...
- 分享一个基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室
实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSoc ...
- 网页实时聊天之js和jQuery实现ajax长轮询
众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...
- 误人子弟的网络,谈谈HTTP协议中的短轮询、长轮询、长连接和短连接
引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接触过,因此LZ便趁着这个机会,好好了解了一下HT ...
- Comet 反Ajax: jQuery与PHP实现Ajax长轮询
原文地址(http://justcode.ikeepstudying.com/2016/08/comet-%E5%8F%8Dajax-%E5%9F%BA%E4%BA%8Ejquery%E4%B8%8E ...
随机推荐
- 设计模式(一)简单工厂(创建型)(Java&&PHP)
面向对象设计的基本原则 单一职责系统中的每一个对象应该只有一个单独的职责,所有对象关注的应该是自身职责的完成. 基本思想:高内聚,低耦合. 开闭原则一个对象对扩展开放,对修改关闭.基本思想:对类的改动 ...
- UML 之 用例图
用例图是指由参与者(Actor).用例(Use Case)以及它们之间的关系构成的用于描述系统功能的静态视图.用例图(User Case)是被称为参与者的外部用户所能观察到的系统功能的模型图,呈现了一 ...
- vue - 使用axios
1. 先安装axios 1.1 npm安装:npm i -D axios 1.2 yarn 安装:yarn add axios --dev 2. 配置main.js,在src目录下. 3. 使用
- 手机网站调试神器之chrome控制台
现在真是一个信息化的时代,每个人手里都拿着一款智能机,上班下班走路坐车之余都会玩玩手机,上上网.于是作为广大网站媒体来说,争抢手机市场无疑是刻不容缓.对于我们Web前端工程师来说,了解并掌握手机编程的 ...
- Linux crond实例
linux系统的定时任务: 1:linux系统自身定期执行的任务工作:系统周期性执行的任务工作,如轮询系统日志,备份系统数据,清理系统缓存等. [root@10-4-5-9 ~]# ll /var/l ...
- 笔记本装ubuntu发热量大该如何缓解?
win7下的双卡技术是optimus, 驱动完善,不会让两个显卡同时满负荷工作, linux下由于驱动软件闭源, xorg的开源驱动没有做这个显卡电源管理, 目前的N卡较好解决方案就是bumblebe ...
- ecshop操作数据库类
ECShop v2.7.2没有使用一些开源的数据库操作类,比如adodb或者PEAR,而是封装了自己的实现.这样做的好处是实现非常轻量,只有一个文件,27Kb,大大减小了分发包的文件大小.另外,当网站 ...
- EMQ ---问题集
1)emqttd 使用 SSL遇到的问题:服务器直接布了一份emqttd ,然后什么都没管,端口默认的ws 8083,wss8084,mqtt 1883,mqtt(ssl) 8883. 结果跑起来之后 ...
- C#:XML操作(简单)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.X ...
- java反射详解及说明
首先写一个Person类: package lltse.base.reflectdemo; public class Person { private String name ="张三&qu ...