欢迎光临散文网 会员登陆 & 注册

网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

2021-05-27 11:03 作者:nickkckckck  | 我要投稿

本文来自“糊糊糊糊糊了”的分享,原题《实时消息推送整理》,有优化和改动。

1、写在前面

对Web端即时通讯技术熟悉的开发者来说,我们回顾网页端IM的底层通信技术,从短轮询、长轮询,到后来的SSE以及WebSocket,使用门槛越来越低(早期的长轮询Comet这类技术实际属于hack手段,使用门槛并不低),技术手段越来越先进,网页端即时通讯技术的体验也因此越来越好。

但上周在编辑《IM扫码登录技术专题》系列文章第3篇的时候忽然想到,之前的这些所谓的网页端即时通讯“老技术”相对于当红的WebSocket,并非毫无用武之地。就拿IM里的扫码登录功能来说,用短轮询技术就非常合适,完全没必要大炮打蚊子上WebSocket。

所以,很多时候没必要盲目追求新技术,相对应用场景来说适合的才是最好的。对于即时通讯网的im和消息推送这类即时通讯技术开发者来说,掌握WebSocket固然很重要,但了解短轮询、长轮询等这些所谓的Web端即时通讯“老技术”仍然大有裨益,这也正是整理分享本文的重要原因。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3555-1-1.html)

2、推荐阅读

[1] 新手入门贴:史上最全Web端即时通讯技术原理详解

[2] 详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

[3] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

3、正文引言

对于IM/消息推送这类即时通讯系统而言,系统的关键就是“实时通信”能力。

从表面意思上来看,“实时通信”指的是:

  • 1)客户端能随时主动发送数据给服务端;

  • 2)当客户端关注的内容在发生改变时,服务器能够实时地通知客户端。

类比于传统的C/S请求模型,“实时通信”时客户端不需要主观地发送请求去获取自己关心的内容,而是由服务器端进行“推送”。

注意:上面的“推送”二字打了引号,实际上现有的几种技术实现方式中,并不是服务器端真正主动地推送,而是通过一定的手段营造了一种“实时通信”的假象。

就目前现有的几种技术而言,主要有以下几类:

  • 1)客户端轮询:传统意义上的短轮询(Short Polling);

  • 2)服务器端轮询:长轮询(Long Polling);

  • 3)单向服务器推送:Server-Sent Events(SSE);

  • 4)全双工通信:WebSocket。

以下正文将针对这几种技术方案,为你一一解惑。

4、本文配套Demo和代码

为了帮助读者更好的理解本文内容,笔者专门写了一个较完整的Demo,Demo会以一个简易聊天室的例子来分别通过上述的四种技术方式实现(代码存在些许bug,主要是为了做演示用,别介意)。

完整Demo源码打包下载:

(请从同步链接附件中下载:http://www.52im.net/thread-3555-1-1.html)

Demo的运行效果(动图):

有兴趣可以自行下载研究学习。

5、理解短轮询(Short Polling)

短轮询的实现原理:

  • 1)客户端向服务器端发送一个请求,服务器返回数据,然后客户端根据服务器端返回的数据进行处理;

  • 2)客户端继续向服务器端发送请求,继续重复以上的步骤,如果不想给服务器端太大的压力,一般情况下会设置一个请求的时间间隔。

逻辑如下图所示:

使用短轮询的优点:基础不需要额外的开发成本,请求数据,解析数据,作出响应,仅此而已,然后不断重复。

缺点也显而易见:

  • 1)不断的发送和关闭请求,对服务器的压力会比较大,因为本身开启Http连接就是一件比较耗资源的事情;

  • 2)轮询的时间间隔不好控制。如果要求的实时性比较高,显然使用短轮询会有明显的短板,如果设置interval的间隔过长,会导致消息延迟,而如果太短,会对服务器产生压力。

短轮询客户的代码实现(片段节选):

var ShortPollingNotification = {

  datasInterval: null,

  subscribe: function() {

    this.datasInterval = setInterval(function() {

      Request.getDatas().then(function(res) {

        window.ChatroomDOM.renderData(res);

      });

    }, TIMEOUT);

    return this.unsubscribe;

  },

  unsubscribe: function() {

    this.datasInterval && clearInterval(this.datasInterval);

  }

}

PS:完整代码,请见本文“4、本文配套Demo和代码”一节。

对应本文配套Demo的运行效果如下(动图):

下面是对应的请求,注意左下角的请求数量一直在变化:

在上图中,每隔1s就会发送一个请求,看起来效果还不错,但是如果将timeout的值设置成5s,效果将大打折扣。如下图所示。

将timeout值设置成5s时的Demo运行效果(动图):

8、什么是WebSocket

8.1 基本介绍

PS:本小节内容引用自《Web端即时通讯实践干货:如何让WebSocket断网重连更快速?》一文的“3、快速了解WebSocket”。

WebSocket诞生于2008年,在2011年成为国际标准,现在所有的浏览器都已支持(详见《新手快速入门:WebSocket简明教程》)。它是一种全新的应用层协议,是专门为web客户端和服务端设计的真正的全双工通信协议,可以类比HTTP协议来了解websocket协议。

(图片引用自《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》)

它们的不同点:

  • 1)HTTP的协议标识符是http,WebSocket的是ws;

  • 2)HTTP请求只能由客户端发起,服务器无法主动向客户端推送消息,而WebSocket可以;

  • 3)HTTP请求有同源限制,不同源之间通信需要跨域,而WebSocket没有同源限制。

它们的相同点:

  • 1)都是应用层的通信协议;

  • 2)默认端口一样,都是80或443;

  • 3)都可以用于浏览器和服务器间的通信;

  • 4)都基于TCP协议。

两者和TCP的关系图:

(图片引用自《新手快速入门:WebSocket简明教程》)

有关Http和WebSocket的关系,可以详读:

《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》

《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》

有关WebSocket和Socket的关系,可以详读:《WebSocket详解(六):刨根问底WebSocket与Socket的关系》.

8.2 技术特征

WebSocket技术特征总结下就是:

  • 1)可双向通信,设计的目的主要是为了减少传统轮询时http连接数量的开销;

  • 2)建立在TCP协议之上,握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器;

  • 3)与HTTP兼容性良好,同样可以使用80和443端口;

  • 4)没有同源限制,客户端可以与任意服务器通信;

  • 5)可以发送文本,也可以发送二进制数据;

  • 6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL.

WebSocket的技术原理如下图所示:

关于WebSocket API方面的知识,这里不再作讲解,可以自己查阅:https://developer.mozilla.org/en-US/docs/Web/API/WebSocket

8.3 浏览器兼容性

WebSocket兼容性良好,基本支持所有现代浏览器。

(上图来自:https://caniuse.com/mdn-api_websocket)

8.4 代码实现

笔者这里采用的是socket.io,是基于WebSocket的封装,提供了客户端以及服务器端的支持。

// 客户端

var WebsocketNotification = {

  // ...

  subscribe: function(args) {

    var connector = args[1];

    this.socket = io();

    this.socket.emit('register', connector);

    this.socket.on('register done', function() {

      window.ChatroomDOM.renderAfterRegister();

    });

    this.socket.on('data', function(res) {

      window.ChatroomDOM.renderData(res);

    });

    this.socket.on('disconnect', function() {

      window.ChatroomDOM.renderAfterLogout();

    });

  }

  // ...

}

 

// 服务器端

var io = socketIo(httpServer);

io.on('connection', (socket) => {

  socket.on('register', function(connector) {

    chatRoom.onConnect(connector);

    io.emit('register done');

    var data = chatRoom.getDatas();

    io.emit('data', { data });

  });

  socket.on('chat', function(message) {

    chatRoom.receive(message);

    var data = chatRoom.getDatas();

    io.emit('data', { data });

  });

});

PS:完整代码,请见本文“4、本文配套Demo和代码”一节。

响应格式如下:

8.5 深入学习

随着HTML5的普及率越来越高,WebSocket的应用也越来越普及,关于WebSocket的学习资料网上很容易找到,限于篇幅本文就不深入展开这个话题。

如果想进一步深入学习WebSocket的方方面面,以下文章值得一读:

《新手快速入门:WebSocket简明教程》

《WebSocket详解(一):初步认识WebSocket技术》

《WebSocket详解(二):技术原理、代码演示和应用案例》

《WebSocket详解(三):深入WebSocket通信协议细节》

《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》

《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》

《WebSocket详解(六):刨根问底WebSocket与Socket的关系》

《理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性》

《微信小程序中如何使用WebSocket实现长连接(含完整源码)》

《八问WebSocket协议:为你快速解答WebSocket热门疑问》

《Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?》

《WebSocket从入门到精通,半小时就够!》

《WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器》

《长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践》

9、本文小结

短轮询、长轮询实现成本相对比较简单,适用于一些实时性要求不高的消息推送,在实时性要求高的场景下,会存在延迟以及会给服务器带来更大的压力。

SSE只能是服务器端推送消息,因此对于不需要双向通信的项目比较适用。

WebSocket目前而言实现成本相对较低,适合于双工通信,对于多人在线,要求实时性较高的项目比较实用。

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3555-1-1.html


网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket的评论 (共 条)

分享到微博请遵守国家法律