Web端即时通信方案知多少?

随着互联网技术的发展,很多Web应用开始追求用户体验,无需刷新就可以让用户可以实时感知信息的变化,即时通信技术在Web中得到了更广泛的应用,常见的有:IM聊天软件、新闻客户端的热点新闻推荐,系统消息提醒,电商产品促销信息推送,在线客服,企业应用的通知和审批流程等等。

作者:张博
单位:中国移动智慧家庭运营中心
原文:https://mp.weixin.qq.com/s/Byy9KNodHcyjFMldE-HdBg

1 什么是即时通信?

即时通信是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流。即时通信技术在Native App中通过TCP、UDP等协议可以轻松实现,在Native应用较为流行。

受HTTP协议以及Web客户端框架限制,想在Web中实现真正的即时通信,可谓是技术上尽脑汁,极尽所能。从传统的短轮询、长轮询到Comet(长轮询的变体)技术,再到HTML5标准发布之后的WebSocket、 SSE这类技术的横空出现,使Web端即时通信的技术方案越来越多,实现也越来越容易。但是对于技术人员面对不同的场景该如何选择更实用的技术方案呢?

2 Web即时通信实现方案有哪些?

2.1 轮询的原理与实现

轮询分为短轮询与长轮询👇

短轮询:是客户端定期向服务器发起请求查询并获取数据,无论是否有数据服务端都立即响应客户端的请求,该方案较为简单不做过多介绍。

长轮询:是比短轮询更有效的一种技术,当服务器收到浏览器请求后如果有数据, 服务器立刻响应请求; 如果没有数据服务器就会hold一段时间,尽可能长时间的保持浏览器的连接打开;这段时间内如果有数据,服务器立刻响应请求; 如果时间到了还没有数据, 则响应http请求;浏览器收到http响应后,立即再发送一个同样http请求查询是否有数据;如此重复下去。下图是长轮询的交互示意图:

Web端即时通信方案知多少?

长轮询浏览器代码实现如下:


/* Client - subscribing to the test events */
subscribe: (callback) => {
const pollUserEvents = () => {
$.ajax({
method: 'GET',
url: 'http://localhost:8080/testEvents',
success: (data) => {
callback(data) // process the data
},
complete: () => {
pollUserEvents();
},
timeout: 30000
})
}

2.2 WebSocket的原理与实现

在2008年中期,开发人员Michael Carter和Lan Hickson敏锐的感受到Comet在实现复杂交互时带来的的苦恼和局限,他们制定了一项计划并引入现代实时双向通信的新标准,创造了WebSocket,并进入了W3C HTML草案标准,2011年RFC 6455-WebSocket协议被发布到了IETF网站。

WebSocket是一个构建在设备TCP/IP堆栈上的瘦传输层,一个独立的基于TCP的协议,为Web应用程序开发人员提供尽可能接近原始的TCP通信层,WebSocket与HTTP唯一的关系是它的握手是由HTTP服务器解释为一个Upgrade请求。

Web端即时通信方案知多少?

WebSocket是一种事件驱动的协议,这意味着可以将其用于真正的实时通信。WebSocket的实现了一次连接,双方多次通信的能力。首先由客户端发出WebSocket连接请求,服务器端进行响应,实现类似TCP握手的动作。这个连接一旦建立起来,在客户端和服务器之间会一直保持该连接,两者之间可以直接的进行数据的互相传送,并且在连接被关闭前可以进行多次交互。

WebSocket浏览器侧代码实现:

const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost/ws');
ws.on('open', function open() {
    ws.send('something');
});


ws.on('message', function incoming(data) {
    console.log(data);
});

WebSocket服务端代码实现:


const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(message) {
    console.log('received: %s', message);
    });
    ws.send('something');
});

2.3 SSE的原理与实现

SSE是Server-Sent Events的简称,是一种可以主动从服务端推送消息给浏览器的技术。SSE也是使用HTTP协议进行交互,严格地说HTTP协议无法做到服务器主动推送信息给浏览器,都是浏览器主动去请求服务器端获取最新的数据,SSE技术使服务器与浏览器之间维护一个HTTP长连接,当有新数据时,服务端可以通过这个长连接将数据发送给浏览器。

Web端即时通信方案知多少?

浏览器主动请求建立一个格式为text/event-stream的stream流 ,服务器给浏览器发送的数据不是一次性的数据包,而是一个stream流,并且浏览器不会关闭连接,会一直等着服务器发送新的数据流报文。

客户端代码实现:


var SSENotification = {
  source: null,
  subscribe: function() {
    if ('EventSource' in window) {
      this.source = new EventSource('/sse');


      this.source.addEventListener('message', function(res) {
        const d = res.data;
        window.ChatroomDOM.renderData(JSON.parse(d));
      });
    }
    return this.unsubscribe;
  },
  unsubscribe: function () {
    this.source && this.source.close();
  }
}

服务器端代码实现:


router.get('/sse', function(req, res) {
  const connectors = chatRoom.getConnectors();
  const messages = chatRoom.getMessages();
  const response = { code: 200, data: { connectors: connectors, messages: messages } };


  res.writeHead(200, {
    "Content-Type":"text/event-stream",
    "Cache-Control":"no-cache",
    "Connection":"keep-alive",
    "Access-Control-Allow-Origin": '*',
  });


  res.write("retry: 10000\n");
  res.write("data: " + JSON.stringify(response) + "\n\n");


  var unsubscribe = Event.subscribe(function() {
    const connectors = chatRoom.getConnectors();
    const messages = chatRoom.getMessages();
    const response = { code: 200, data: { connectors: connectors, messages: messages } };
    res.write("data: " + JSON.stringify(response) + "\n\n");
  });


  req.connection.addListener("close", function () {
    unsubscribe();
  }, false);
});

3 Web即时通信方案对比 

三种即时通信技术方案各有优缺点,三种技术方案特性对比如下:

Web端即时通信方案知多少?

从对比可以得出👇

长轮询:兼容性好,实现容易;但是由于需要不停向服务器请求查询,很多时候都是无效报文,效率低,客户端数量多时服务端的压力较大;适用于扫码登录,流程状态变化等场景。

WebSocket:支持双向通信,可以实现真正的实时通信,支持二进制数据传输,基本可以胜任各种即时通信场景,而且由于WebSocket的首部信息很小,报文有效载荷高,在海量并发和客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势;但是WebSocket协议相对于HTTP协议较复杂,不支持断线重连,有一定维护成本,因此实际应用中需要基于WebSocket开源SDK进行开发;适用于大型聊天App或大型多人在线游戏的场景。

SSE:属于轻量级方案,主流浏览器都已经支持,使用简单,默认支持断线重连,支持自定义事件类型;但是SSE长连接只支持从服务器向客户端发数据,并且不支持二进制传输(需要编码后传输)。适用于服务器持续向客户端发送数据的场景,如:实时股价流图、在线音视频播放、监视器客户端查看服务器实时信息等。

4 结束语 

轮询、WebSocket、SSE三种技术方案中该如何选择?在消息推送时SSE似乎是我们解决问题的最终选择;但是SSE对于大型游戏、聊天室时又有很多力不从心,不如WebSocket全面;而面对扫码登录等简单场景时轮询似乎更加简单便捷。因此Web端即时通信方案并不能简单的说古老的技术会被新技术替代,项目实施中我们要合理选择,采用更简单、更高效的方案来完成需求。

➺ 参考文献 

[1] WebSocket API文档 https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket.

[2] SSE API文档 https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource.

[3] Comet技术详解:基于HTTP长连接的Web端实时通信技术https://blog.csdn.net/hellojackjiang2011/article/details/103622319.

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论