暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

WebSocket详解

IT那活儿 2023-06-07
868
点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!



WebSocket概述



当前大多数应用程序都是基于B/S架构实现,对于B/S架构,HTTP请求一般通过Ajax、或者Vue项目使用Axios来发送到服务器,服务器接受请求后进行处理,然后返回HTTP响应。这种HTTP请求的方向是固定的,只能从浏览器发送到服务器,不能反方向的从服务器发送至浏览器。HTTP请求方式如上图所示,由此可见,HTTP协议具有一个缺陷:通信只能由客户端发起

来看一个实际场景,我们经常碰到扫码登录的情况,浏览器展示一个二维码,提示通过手机扫码登录,用户通过手机扫码,向服务器发送登录请求。在这个过程中,浏览器每隔一段时间询问服务器登录结果。这种方式只能是客户端向服务器发出请求,服务器返回查询结果,HTTP协议做不到服务器主动向客户端推送信息。上图展示了扫码登录的流程,可见服务器的登录结果无法向浏览器主动推送。这种单向请求的特点,注定了服务器如果有连续的状态变化,客户端要获知就非常麻烦。只能在客户端使用轮询方式,每隔一段时间,就发出一个询问请求去了解服务器有没有新消息。
轮询需要不停的发起HTTP连接,不仅效率低,浪费带宽,实时性差,对服务器压力也大。WebSocket 就是在这种情况下发明的。

WebSocket在2008年提出,2011年成为标准,它是HTML5新增的协议,可以在浏览器和服务器之间建立一个全双工的通信通道。WebSocket允许服务端主动向客户端推送数据,可以使客户端和服务器之间的数据交换变得更加简单。




WebSocket原理



在WebSocket协议中,浏览器和服务器只需完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。

WebSocket通信流程如下:
1. 浏览器发起HTTP请求,申请建立WebSocket连接
此时以特定的模式访问一个URL,这个URL有两种模式,分别是ws和wss,对应HTTP协议中的HTTP和HTTPS。在请求头中有一个Connection:Upgrade字段,表示客户端想要对协议进行升级,另外还有一个Upgrade:websocket字段,表示客户端想要将请求协议升级为WebSocket协议。
2. 服务器同意协议升级
服务器响应状态码101,同意将协议升级为WebSocket。
3. 相互发送数据
在握手完成之后,文本消息或者其他二进制消息就可以同时在两个方向上进行发送,而不需要关闭或重建连接。此时的客户端和服务端关系是对等的,它们可以互相向对方主动发送消息。
WebSocket优点:
  • 1)容易实现。WebSocket协议建立在TCP协议基础上,服务器端容易实现,不同的语言都有支持。
  • 2)控制开销较少。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。
  • 3)实时性更强。由于TCP协议是全双工的,所以服务器可以随时主动给客户端发送数据,延迟明显更少。
  • 4)保持连接状态。WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。
  • 5)更好的二进制支持。WebSocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  • 6)WebSocket没有同源限制,客户端和任意服务端都可以通信。
  • 7)可以支持扩展。WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。



WebSocket实现方式



在Spring框架中已经实现了WebSocket的基本功能,完成了HTTP协议升级为WebSocket协议的过程,封装了很多通信细节。所以WebSocket的开发就是去完成一些具体的业务功能,实现方式主要有两种,一种是针对简单需求的基于Java注解的方式,另一种是基于Spring提供的上层封装实现。

接下来以基于常见的Spring方式实现一个后端向前端发送心跳的WebSocket例子。
1. 客户端(浏览器)实现
客户端主要通过let ws = new WebSocket(url) 这个API来创建WebSocket对象,其中参数url格式为:ws://ip地址:端口/资源名称。该对象包括4个处理事件,onopen事件用于连接建立时触发,onmessage事件用于接收到服务端消息时触发,onerror事件用于发生错误时触发,onclose事件用于连接关闭时触发,还有一个send方法用于向后端发送数据。
2. 服务端实现
首先需要引入WebSocket依赖。
实现握手拦截器,用于在请求握手前后添加自定义操作。新建自定义拦截器,继承HttpSessionHandshakeInterceptor抽象类,选择实现其中的beforeHandshake和afterHandshake方法来分别在握手前和握手后添加处理逻辑。
实现WebSocket处理程序,用于添加连接前、连接中、连接后的处理逻辑。新建自定义处理类,继承AbstractWebSocketHandler抽象类,类似于前端的4个处理事件,此处也需要实现4个处理方法分别用于在建立连接、收到客户端消息、传输异常、连接关闭情况下添加处理逻辑。
在上述处理程序中添加一个定时向浏览器发送心跳的方法,可以看到WebSocket向客户端发送消息主要是通过WebSocketSession的sendMessage方法实现的。
实现WebSocket配置程序。新建WsConfig配置类实现WebSocketConfigurer接口,该接口只有一个registerWebSocketHandlers注册方法,将上述自定义握手拦截器、处理程序注册到WebSocketHandlerRegistry中并指定访问资源名称。
3. 运行效果
运行程序,测试该WebSocket连接,可见能成功接收到服务端主动推送过来的心跳消息。

总 结:

HTTP请求只能从浏览器往服务器发送,无法反向从服务器发往浏览器,对于需要服务器主动通知浏览器的场景无法满足,此时可以使用WebSocket。
WebSocket是从HTML5开始支持的全双工通信协议,简单说就是浏览器和服务器都可以主动发起请求。它是基于现有的HTTP请求做了一个协议升级,首先从浏览器发起一个HTTP协议请求,地址为(ws:)开头,同时header里会携带一些参数告知服务器这是一个协议升级请求,服务器收到后会返回一个101状态码表示同意协议升级,升级完后就是一个WebSocket协议,前后端都可以主动发起请求。
WebSocket实现方式也很多,常见的有基于Java注解的方式,基于Spring框架的方式,及其他封装好的框架等。
WebSocket在实时通信的场景中应用非常广泛,例如即时通讯、视频弹幕、协同编辑、大屏实时更新、扫码登录、实时监控等。

END


本文作者:事业二部(上海新炬中北团队)

本文来源:“IT那活儿”公众号

文章转载自IT那活儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论