如何实现服务端向客户端推送数据

简介: 常见的http协议只能从客户端主动向服务端请求数据,而服务端无法向客户端发送数据.本文通过介绍几种方式来实现上述功能.

以微信朋友圈为例:
朋友圈提供动态点赞与评论功能,我们需要一种机制或方法保证用户在使用朋友圈过程中能相对实时地收到其他用户的点赞和评论消息。简单来说,就是实现双向通信。常用的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,并发送消息通知,动态发布者的客户端收到通知后会在浏览动态页右上角显示小红点,提醒用户有未读消息。

相关文章
|
JavaScript
HTTP/2 协议-服务端主动推送消息
HTTP/2 协议-服务端主动推送消息
641 0
|
网络协议 Python
python中socket客户端发送和接收数据
【4月更文挑战第7天】本教程聚焦TCP客户端数据发送与接收。使用Python的`socket`模块,通过`send()`发送字节串至服务器,如`client_socket.send(message_bytes)`;用`recv()`接收数据,如`received_data = client_socket.recv(buffer_size)`。异常处理确保网络错误时程序健壮性,例如`try-except`捕获`socket.error`。理解和掌握这些基础操作对于构建稳定的TCP客户端至关重要。
2408 1
|
Go
golang run时报undefined错误【已解决】
golang run时报undefined错误【已解决】
3670 0
golang run时报undefined错误【已解决】
|
10月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
650 3
|
JavaScript 前端开发 Go
动态加载与异步加载 JavaScript 详解:加载远程js,加载成功后执行回调函数
动态加载与异步加载 JavaScript 详解:加载远程js,加载成功后执行回调函数
2326 2
一文讲明 网络调试助手的基本使用 NetAssist
文章介绍了网络调试助手NetAssist的基本使用方法,包括创建客户端和服务端,模拟网络连接和数据发送,并通过Java代码示例展示了客户端与服务端之间的通信过程。
一文讲明 网络调试助手的基本使用 NetAssist
|
11月前
|
前端开发 Java API
Swagger接口文档 —— 手把手教学,全方位超详细小白能看懂,百分百能用Java版
本文提供了一份详细的Swagger接口文档生成工具的使用教程,包括了导入依赖、配置类设置、资源映射、拦截器配置、Swagger注解使用、生成接口文档、在线调试页面访问以及如何设置全局参数(如token),旨在帮助Java开发者快速上手Swagger。
6576 0
Swagger接口文档 —— 手把手教学,全方位超详细小白能看懂,百分百能用Java版
|
网络协议 Java
JAVA实现心跳检测【长连接】
这篇文章介绍了Java中实现心跳检测机制的方法,包括心跳机制的简介、实现方式、客户端和服务端的代码实现,以及具体的测试结果。文中详细阐述了如何通过自定义心跳包和超时检测来维持长连接,并提供了完整的客户端和服务端示例代码。
JAVA实现心跳检测【长连接】
|
UED
【Qt 学习笔记】Qt窗口 | 工具栏 | QToolBar的使用及说明
【Qt 学习笔记】Qt窗口 | 工具栏 | QToolBar的使用及说明
1524 2
|
SQL 数据处理 数据库
DELETE 和 TRUNCATE 语句之间的详细区别
【8月更文挑战第31天】
1616 0