zl程序教程

您现在的位置是:首页 >  其他

当前栏目

webim 实现实时通讯的 4 种方式

2023-03-14 22:59:15 时间

本文前半段主要节选自:WebSocket ,后半段总结和概括自沈剑大佬的两篇文章和文章评论http如何像tcp一样实时的收消息?网页端收消息,究竟是推还是拉?,完整参考见文末。

webim 是什么

即时通信(Instant Message,IM),比如 QQ、微信。webim 就是通讯应用的浏览器版本。

webim 实现实时通讯的 4 种方式

1、HTTP

http是一种无状态协议,每次请求和响应就携带有大量的header头,每当一次会话完成后,服务端都不知道下一次的客户端是谁,需要每次知道对方是谁,才进行相应的响应,因此本身对于实时通讯就是一种极大的障碍,而且因为每次都得携带上 header,加大了网络开销和服务端的解析开销,进一步降低了通信效率。

最重要的是,需要客户端主动发,服务端被动发,也就是一次请求,一次响应,服务器无法主动给某个客户端发送数据。

2、long poll(长轮询)

就是客户端发起长轮询,如果服务端的数据没有发生变更,会 hold 住请求,直到服务端的数据发生变化,或者等待一定时间超时才会返回。返回后,客户端又会立即再次发起下一次长轮询。

伪长连接。

优点:

  • 通讯实时性高。服务端数据发生变更后,长轮询结束,立刻返回响应给客户端。
  • 服务端压力小。长轮询的间隔期一般很长,例如 30s、60s,并且服务端 hold 住连接不会消耗太多服务端资源。

3、Ajax轮询

按照一定的频率,每隔一段时间就给服务端发起一次 http 请求,查询有没有新消息,如果有,就返回,如果没有等待相同的时间间隔再次询问。以此实现浏览器跟服务器的近实时通信。

Ajax轮询存在的问题:

  1. 通讯实时性一般,最坏情况下需要等待一个间隔周期才能收到服务端的数据。
  2. 服务端压力较大。频繁的轮询会给服务端造成很大的压力,浪费服务端资源。
  3. 通讯实时性和服务端压力无法中和。加大轮询频率,实时性提高,服务端压力增加;减小轮询频率,服务端压力降低,但是通讯延迟加大,实时性降低。

4、websocket(当前web实时通信的首选技术)

socket 翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。

WebSocket协议是基于 TCP 的一种新的网络协议,和 http 协议一样属于应用层协议,是一种让客户端和服务器之间能进行双向实时通信的技术,实现了“真·长链接”,也就是连接可持久化的意思。(在2008年诞生,2011年成为国际标准,协议标识符是ws,如果加密,则为wss,服务器网址就是 URL)

1456655-20230217004208978-787626327.png

WebSocket有以下特点:

  • 是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动发起请求。而HTTP长连接基于 HTTP,是传统的客户端对服务器发起请求的模式。
  • HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header(比如cookie,jwt等),信息交换效率很低。Websocket协议通过第一个 request 建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据,因为需要 header 的东西在第一次建立连接时就做完了,后面直接用这个就行。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势。这显然和原有的HTTP协议有区别所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5)

问题

问:web实时通讯是怎么实现的?http如何像tcp一样实时的收消息?

通过 long poll 长轮询来实现的。业内主流做法,同时在线量很高很高的webim(比如web qq,百度hi等),基本上都是这样实现的,大部分产品一般有一个comet之类开头的子域名专门提供这个服务。之所以不用 websocket,是因为它需要浏览器和web-server的支持,websocket有些浏览器/web-server不支持

问:长轮询的方式会不会导致 web 服务器的连接数爆掉

现在普通的 web-server 单机都能抗住千级别的连接数,如果需要抗住更多连接,可以通过水平扩展 web 服务器来解决。如果反向代理有瓶颈,则水平扩展反向代理,一般来说,一个 nginx 轻松 hang 住几十万链接。

问:如果上一个 http 连接返回期间,服务器产生了新的消息怎么办?怎么保证下个连接会刚好请求到同个服务器

服务端消息暂存入消息池中,下一个消息连接到达后将消息立刻带回客户端。通过 Nginx 的 ip hash 可以同个用户的连接每次都由同一个服务端机器处理。

问:如果服务端生成消息非常快,长轮询性能是不是比普通轮询性能还低

(1)对于同一个用户(uid),不会一秒钟上百条消息的。(2)如果真的同一个uid消息量非常大,可以在服务端批量返回,以减少交互次数

问:如果用户杀掉了这个app进程,app还是能收到新消息息提醒,怎么实现的?

这个是APP服务驻留的问题

问:每个连接都需要一个线程来处理吗

不需要,每个连接不需要一个线程维持,每个连接只是一个文件,只占有一个收发队列。

问:如果服务端产生新消息的瞬间,连接恰好超时,这样会丢数据吗

不会丢数据,有 ack 机制和本地队列

问:长轮询夯住的请求放在哪,怎么唤醒夯住的请求

夯住的请求放到上下文里,通过 notify 可实时唤醒请求。

问:微信扫码登录、扫码支付,支付成功消息回调也是长轮训

是的

问:有消息返回前,用户关闭browser了应该怎么办

此时消息会不可达,如果消息很重要,需要再存离线。

问:为什么 CS架构 可以实现全双工通信,BS 架构却只能浏览器发起请求

  • BS(browser/Server) 架构的通信协议是 http 。浏览器所有页面共用一个 80 端口,每个页面没有独占的端口号,所以服务器无法主动给某个页面发送数据。
  • CS(Client/Server)架构的通信协议是 WebSocket,每个客户端都独占一个端口号,所以允许服务端主动向客户端推送数据。

完整参考

WebSocket

【星课堂】一文带你了解webSocket

webSocket和Socket之间的区别联系

http如何像tcp一样实时的收消息?

网页端收消息,究竟是推还是拉?