以微信朋友圈为例:
朋友圈提供动态点赞与评论功能,我们需要一种机制或方法保证用户在使用朋友圈过程中能相对实时地收到其他用户的点赞和评论消息。简单来说,就是实现双向通信。常用的Http协议通信只能由客户端发起,服务端接收到请求并做出应答,显得十分被动,这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。
经过调研,找到以下几种实现双向通信的方式:
1.轮询(polling):让客户端隔个几秒就发送一次请求,询问服务器是否有新信息。
用大白话举例就是:
while True: 客户端:妹子,请你吃饭有空吗?(Request)
服务端:没有!(Response)
客户端:妹子,请你吃饭有空吗?(Request)
服务端:没有。。(Response)
客户端:妹子,请你吃饭有空吗?(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:妹子,请你吃饭有空吗?(Request)
服务端:好啦好啦,有啦。(Response)
客户端:妹子,请你吃饭有空吗?(Request)
服务端:。。。。。没。。。。没。。。没有(Response)
- 优点:实现简单,无需做过多的更改
- 缺点:轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担
2.长轮询(long-polling):长轮询其实原理跟轮询差不多,都是采用轮询的方式,不过采取的是阻塞模型,也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
还是用大白话举例:
while True:
客户端:妹子,请你吃饭有空吗?没有的话就等有了再返回给我吧!(Request)
服务端:(额。。现在好忙,先不回复他,电话先不挂。)
服务端:现在有空了。(Response)
客户端:妹子,请你吃饭有空吗?没有的话就等有了再返回给我吧!(Request)
服务端:(额。。现在好忙,先不回复他,电话先不挂。)
服务端:现在有空了。(Response)
- 优点:比 polling 做了优化,有较好的时效性
- 缺点:保持连接会消耗资源;服务器没有返回有效数据,程序超时
3.iframe流(streaming):iframe流方式是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长连接,服务器向iframe传输数据,来实时更新页面。
while True:
客户端:妹子,请你吃饭有空吗?(Request)
服务端:您好,您所拨打的用户正在通话中,请稍后再拨。(503 Server Unavailable)
客户端:妹子,请你吃饭有空吗?(Request)
服务端:您好,您所拨打的用户正在通话中,请稍后再拨。(503 Server Unavailable) 服务端忙的要死:(我要更多的资源,资源。。。)
- 优点:消息能够实时到达;浏览器兼容好
- 缺点:服务器维护一个长连接会增加开销;IE、chrome、Firefox会显示加载没有完成,图标会不停旋转。
经过个人的评估,得出了最优解
WebSocket,它是基于TCP/IP协议,独立于HTTP协议的通信协议,而且能实现客户端与服务端双向实时响应(客户端 ⇄ 服务端)。
客户端:我要建立WebSocket协议,需要的服务:chat,WebSocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为WebSocket协议(HTTP Protocols Switched)
客户端:你有事的时候记得要找我噢!
服务端:ok,有事的时候会找你的。 服务端:我想吃炸鸡了。 服务端:我想喝奶茶了。 服务端:我不开心了。
服务端:balabalabalabala。。。
选择原因:
- 支持双向通信,实时性更强
- 可以发送文本,也可以发送二进制数据
- 减少通信量:只要建立起WebSocket连接,就希望一直保持连接状态。和HTTP相比,不但每次连接时的总开销减少,而且由于WebSocket的首部信息很小,通信量也相应减少了。
- 方便与springboot集成,降低开发成本
相对于传统的HTTP每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket是类似Socket的TCP长连接的通讯模式,一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket连接或Server端断掉连接前,不需要客户端和服务端重新发起连接请求。 在海量并发和客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。
具体的技术实现如下(模拟朋友圈):
当用户进入朋友圈,前端监听到对应事件,带上当前用户的token开始与服务端建立websocket连接,服务端接收到请求,解析请求的token,获取到该用户的openId,把它作为key,缓存当前连接的session()。当其他用户对该用户的动态点赞或评论,服务端接收到请求并执行完相关的逻辑后会查找session缓存中是否存在该动态发布者的session,若存在(该用户在线),则找到该session,并发送消息通知,动态发布者的客户端收到通知后会在浏览动态页右上角显示小红点,提醒用户有未读消息。