基于HTTP的长轮询实现

Web客户端与服务器之间基于Ajax(http)的常用通信方式,分为短连接与长轮询。
短连接:客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
在长轮询机制中,客户端像传统轮询一样从服务器请求数据。然而,如果服务器没有可以立即返回给客户端的数据,则不会立刻返回一个空结果,
而是保持这个请求等待数据到来(或者恰当的超时:小于ajax的超时时间),之后将数据作为结果返回给客户端。
长轮询机制如下图所示:
在这里插入图片描述
web客户端代码如下:

//向后台长轮询消息
    function longPolling(){
    
    
        $.ajax({
    
    
            async : true,//异步
            url : 'longPollingAction!getMessages.action', 
            type : 'post',
            dataType : 'json',
            data :{
    
    },
            timeout : 30000,//超时时间设定30秒
            error : function(xhr, textStatus, thrownError) {
    
    
                longPolling();//发生异常错误后再次发起请求
            },
            success : function(response) {
    
    
                message = response.data.message;
                if(message!="timeout"){
    
    
                    broadcast();//收到消息后发布消息
                }
                longPolling();
            }
        });
    }

web服务器端代码如下:

public class LongPollingAction extends BaseAction {
    
    
    private static final long serialVersionUID = 1L;
    private LongPollingService longPollingService;
    private static final long TIMEOUT = 20000;// 超时时间设置为20秒
 
    public String getMessages() {
    
    
        long requestTime = System.currentTimeMillis();
        result.clear();
        try {
    
    
            String msg = null;
 
            while ((System.currentTimeMillis() - requestTime) < TIMEOUT) {
    
    
                msg = longPollingService.getMessages();
                if (msg != null) {
    
    
                    break; // 跳出循环,返回数据
                } else {
    
    
                    Thread.sleep(1000);// 休眠1秒
                }
            }
            if (msg == null) {
    
    
                result.addData("message", "timeout");// 超时
            } else {
    
    
                result.addData("message", msg);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
 
        return SUCCESS;
    }
    
    public LongPollingService getLongPollingService() {
    
    
        return longPollingService;
    }
 
    public void setLongPollingService(LongPollingService longPollingService) {
    
    
        this.longPollingService = longPollingService;
    }
 
}

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

用通俗易懂的话来说,就是客户端不停的向服务器发送请求以获取最新的数据信息。这里的“不停”其实是有停止的,只是我们人眼无法分辨是否停止,它只是一种快速的停下然后又立即开始连接而已。

二、长连接、长轮询的应用场景

长连接、长轮询一般应用与WebIM、ChatRoom和一些需要及时交互的网站应用中。其真实案例有:WebQQ、Hi网页版、Facebook
IM等。 如果你对服务器端的反向Ajax感兴趣,可以参考这篇文章 DWR 反向Ajax
服务器端推的方式:http://www.cnblogs.com/hoojo/category/276235.html

三、优缺点

  • 轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
    优点:后端程序编写比较容易。
    缺点:请求中有大半是无用,浪费带宽和服务器资源。
    实例:适于小型应用。

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

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

  • Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。
    优点:实现真正的即时通信,而不是伪即时。
    缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。
    实例:网络互动游戏。

四、实现原理

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

  1. 轮询的建立
    建立轮询的过程很简单,浏览器发起请求后进入循环等待状态,此时由于服务器还未做出应答,所以HTTP也一直处于连接状态中。
  2. 数据的推送
    在循环过程中,服务器程序对数据变动进行监控,如发现更新,将该信息输出给浏览器,随即断开连接,完成应答过程,实现“服务器推”。
  3. 轮询的终止
    轮询可能在以下3种情况时终止:
    3.1. 有新数据推送
    当循环过程中服务器向浏览器推送信息后,应该主动结束程序运行从而让连接断开,这样浏览器才能及时收到数据。
    3.2. 没有新数据推送
    循环不能一直持续下去,应该设定一个最长时限,避免WEB服务器超时(Timeout),若一直没有新信息,服务器应主动向浏览器发送本次轮询无新信息的正常响应,并断开连接,这也被称为“心跳”信息。
    3.3. 网络故障或异常
    由于网络故障等因素造成的请求超时或出错也可能导致轮询的意外中断,此时浏览器将收到错误信息。
  4. 轮询的重建
    浏览器收到回复并进行相应处理后,应马上重新发起请求,开始一个新的轮询周期。

猜你喜欢

转载自blog.csdn.net/Number_oneEngineer/article/details/119573271
今日推荐