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长轮询的更多相关文章

  1. Tornado长轮询和WebSocket

    Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息. 短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应. ...

  2. tornado 10 长轮询和 websocket

    tornado 10 长轮询和 websocket 一.长轮询 #在网页,我们经常扫码登录,那么问题来了,前端是如何知道用户在手机上扫码登录的呢 这里就需要用到长轮询 #长轮询 #客户端能够不断地向服 ...

  3. http长轮询&短轮询

    http 协议介绍: http 协议是请求/响应范式的, 每一个 http 响应都是由一个对应的 http 请求产生的; http 协议是无状态的, 多个 http 请求之间是没有关系的. http ...

  4. 三周,用长轮询实现Chat并迁移到Azure测试

    公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都花在这上面了.简单地说就是用MVC4基于长 ...

  5. 用.NET MVC实现长轮询,与jQuery.AJAX即时双向通信

    两周前用长轮询做了一个Chat,并移植到了Azure,还写了篇博客http://www.cnblogs.com/indream/p/3187540.html,让大家帮忙测试. 首先感谢300位注册用户 ...

  6. 分享一个基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室

    实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSoc ...

  7. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  8. 误人子弟的网络,谈谈HTTP协议中的短轮询、长轮询、长连接和短连接

    引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接触过,因此LZ便趁着这个机会,好好了解了一下HT ...

  9. Comet 反Ajax: jQuery与PHP实现Ajax长轮询

    原文地址(http://justcode.ikeepstudying.com/2016/08/comet-%E5%8F%8Dajax-%E5%9F%BA%E4%BA%8Ejquery%E4%B8%8E ...

随机推荐

  1. Unity3d笔试题大全

    1.       [C#语言基础]请简述拆箱和装箱. 答: 装箱操作: 值类型隐式转换为object类型或由此值类型实现的任何接口类型的过程. 1.在堆中开辟内存空间. 2.将值类型的数据复制到堆中. ...

  2. SQL Server基础知识三十三问 (1-7)

    1. SQL Server运行在什么端口上? 可以被修改么? 答: 1433端口. 可以修改的, 在SQL Server Configuration Manager的SQL Server Networ ...

  3. 作用JavaScript访问和操作数据库

    JS操作 Access 数据库 <SCRIPT LANGUAGE="JavaScript"> <!-- var filePath = location.href. ...

  4. 我的Mac必备软件

    1.Svn工具: Cornerstone_v2.7.10 2.iPhone配置文件管理 iPhoneConfigUtility.dmg 3.有道 for mac http://cidian.youda ...

  5. 给电脑装完系统之后,发现U盘少了几个G!

    我的U盘是8个G的,有一次用U盘给电脑装完系统,过了几天后再次用的时候发现U盘 突然少了几个G,刚开始不知道怎么回事,然后就格式化U盘,但是格式化之后没有任何 变化. 在网上搜了一下,说是U盘有可能被 ...

  6. android.content.res.Resources$NotFoundException: String resource ID #0x0

    仔细检查是不是在settext的时候设置进去的时int属性的值,所以android会认为这是在strings中的值,所以会拿着这个int值当做string的id值去找,结果当然是找不到的.

  7. TCP/IP编程 - 1) 基础知识

    1. What Is a Socket?(什么是套接字) A socket is an abstraction through which an application may send and re ...

  8. vue - 子路由-路由嵌套

    描述:子路由,也叫路由嵌套,采用在children后跟路由数组来实现,数组里和其他配置路由基本相同,需要配置path和component,然后在相应部分添加<router-view/>来展 ...

  9. 小贝_redis高级应用-公布与订阅

    redis高级应用-公布与订阅 一.公布与订阅(pub/sub)功能 二.公布与订阅(pub/sub)机制 三.redis公布与订阅(pub/sub)的实现 一.公布与订阅(pub/sub)功能 Pu ...

  10. JUnit单元测试基础要点

    JUnit单元测试基础要点 1.JUnit是一种测试代码的框架,测试的目的是:保证代码没错,而不是保证代码正确. 2.测试类一般不要和目标类放在一起,但编译成的class文件是放在一起的. 3.单元测 ...