WEB通信之 长连接、长轮询(long polling)

一、什么是长连接、长轮询?

长连接:基于HTTP的长连接,是一种通过长轮询方式实现”服务器推”的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性。
一般都是用socket实现长连接
http请求一般是短连接:一次请求结束,就会断开与服务器的连接,服务器不能
主动推送数据到客户端,而只能由客户端发起请求。

a) AJAX短连接实现网页聊天
WEB通信之 长连接、长轮询(long polling)_第1张图片
常规的短连接模式下,都是通过不间断的刷新请求实现的,比如每隔3s发送一次AJAX请求,3s更新一下数据,然后就这样不间断的刷新下去,直到用户关闭网页。
弊端:如果用户很长时间没有操作,每次刷新都不会返回新数据!


二.长连接方式

它的刷新是根据数据来执行的,如果有新数据返回就接收并解析显示数据。如果一段时间内用户没有操作则连接处于睡眠状态,一直等待用户输入或请求超时,然后发起下一个ajax请求。
WEB通信之 长连接、长轮询(long polling)_第2张图片
这样做的好处是,每个消息都会即时推送到客户端,延迟极少;另外每次请求都是有意义的,与短连接对比,效率要高很多。但对于一个用户量很多,并且操作非常频繁的网站,长连接模式也会出现过于频繁的刷新问题。目前IE对于HTTP连接数是有限制的,每个网页只能同时进行两个长连接,第三个长连接会被阻塞。

轮询: 客户端定时向服务器发送AJAX请求。
缺点:请求中大半无用,浪费带宽和服务器资源
优点:后端程序编写比较容易。
实例:适于小型应用。

长轮询:客户端向服务器发送AJAX请求,服务器接到请求后hold住连接
直到有新的信息or新的数据才返回响应信息并关闭连接。客户端处理完再向服务器发送新的请求
优点:在无消息的情况下不会频繁的请求,耗费资源小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:webqq Facebook IM等

长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。 (这里其实只是长连接的一种实现方式而已)
优点:消息即时到达,不发无用请求;管理起来也相对方便。
缺点:服务器维护一个长连接会增加开销。
实例:Gmail聊天

三. 实现原理

所谓长连接,就是要在客户端与服务器之间创建和保持稳定可靠的连接。其实它是一种很早就存在的技术,但是由于浏览器技术的发展比较缓慢,没有为这种机制的实现提供很好的支持。所以要达到这种效果,需要客户端和服务器的程序共同配合来完成。通常的做法是,在服务器的程序中加入一个死循环,在循环中监测数据的变动。当发现新数据时,立即将其输出给浏览器并断开连接,浏览器在收到数据后,再次发起请求以进入下一个周期,这就是常说的长轮询(long-polling)方式。如下图所示,它通常包含以下几个关键过程:

WEB通信之 长连接、长轮询(long polling)_第3张图片

服务器的程序中加入一个死循环,在循环中检测数据的变动,当发生新数据时
,立即将其输出给浏览器并断开连接,浏览器在接收到数据后,再次发起请求以进入下一个周期。
轮询最好设置2种终止条件:
a)有新数据推送
b)没有新数据,避免web服务器超时,设定一个最长时限。

如何轮询
1. 轮询的建立
建立轮询的过程很简单,浏览器发起请求后进入循环等待状态,此时由于服务器还未做出应答,所以HTTP也一直处于连接状态中。
2. 数据的推送
在循环过程中,服务器程序对数据变动进行监控,如发现更新,将该信息输出给浏览器,随即断开连接,完成应答过程,实现“服务器推”。
3. 轮询的终止
轮询可能在以下3种情况时终止:

  • 有新数据推送
    当循环过程中服务器向浏览器推送信息后,应该主动结束程序运行从而让连接断开,这样浏览器才能及时收到数据。

  • 没有新数据推送
    循环不能一直持续下去,应该设定一个最长时限,避免WEB服务器超时(Timeout),若一直没有新信息,服务器应主动向浏览器发送本次轮询无新信息的正常响应,并断开连接,这也被称为“心跳”信息

  • 网络故障或异常
    由于网络故障等因素造成的请求超时或出错也可能导致轮询的意外中断,此时浏览器将收到错误信息。

4.轮询的重建
浏览器收到回复并进行相应处理后,应马上重新发起请求,开始一个新的轮询周期。

Ajax轮询

$(function () {

                window.setInterval(function () {

                    $.get("${pageContext.request.contextPath}/communication/user/ajax.mvc", 
                        {"timed": new Date().getTime()}, 
                        function (data) {
                            $("#logs").append("[data: " + data + " ]
"
); }); }, 3000); });

客户端实现的就是用一种普通轮询的结果,比较简单。利用setInterval不间断的刷新来获取服务器的资源,这种方式的优点就是简单、及时。缺点是链接多数是无效重复的;响应的结果没有顺序(因为是异步请求,当发送的请求没有返回结果的时候,后面的请求又被发送。而此时如果后面的请求比前面的请求要先返回结果,那么当前面的请求返回结果数据时已经是过时无效的数据了);请求多,难于维护、浪费服务器和网络资源。

iframe
和AJAX一样可以实现页面异步更新。iframe是内嵌网页,所以在iframe标签中
src填入请求的url就相当于get,返回数据,可以用jquery的load方法读取。

            $(function () {

                window.setInterval(function () {
                    $("#logs").append("[data: " + $($("#frame").get(0).contentDocument).find("body").text() + " ]
"
); $("#frame").attr("src", "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime()); // 延迟1秒再重新请求 window.setTimeout(function () { window.frames["polling"].location.reload(); }, 1000); }, 5000); });

这里的客户端程序是利用隐藏的iframe向服务器端不停的拉取数据,将iframe获取后的数据填充到页面中即可。同ajax实现的基本原理一样,唯一不同的是当一个请求没有响应返回数据的情况下,下一个请求也将开始,这时候前面的请求将被停止。如果要使程序和上面的ajax请求一样也可以办到,那就是给每个请求分配一个独立的iframe即可。

ajax实现长连接

$(function () {

                (function longPolling() {

                    $.ajax({
                        url: "${pageContext.request.contextPath}/communication/user/ajax.mvc",
                        data: {"timed": new Date().getTime()},
                        dataType: "text",
                        timeout: 5000,
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            $("#state").append("[state: " + textStatus + ", error: " + errorThrown + " ]
"
); if (textStatus == "timeout") { // 请求超时 longPolling(); // 递归调用 // 其他错误,如网络错误等 } else { longPolling(); } }, success: function (data, textStatus) { $("#state").append("[state: " + textStatus + ", data: { " + data + "} ]
"
); if (textStatus == "success") { // 请求成功 longPolling(); } } }); })(); });

上面这段代码就是Ajax的方式完成长连接。
主要优点:就是和服务器始终保持一个连接。如果当前连接请求成功后,将更新数据并且继续创建一个新的连接和服务器保持联系。如果连接超时或发生异常,这个时候程序也会创建一个新连接继续请求。这样就大大节省了服务器和网络资源,提高了程序的性能,从而也保证了程序的顺序。


总结

目前来说,HTTP/1.1 已经是keep-alive,也就是默认是持久连接。 不过所谓的持久连接指的是TCP层面上的 重用TCP连接,消除连接以及关闭的延时。
而长连接说的不是HTTP持久连接,而是一种为了减少客户端请求次数的,让服务器接收到请求后hold住连接,然后直到有新的数据返回给客户端才关闭连接的”服务器推”技术。 和HTTP持久连接很像,但是持久连接:是事务处理结束后仍然保持在打开状态的TCP连接!
也就是说是强调重用 现存的TCP连接,为了未来的多次请求也能利用这个持久连接!!

你可能感兴趣的:(前端)