简单介绍
1、webSocket是HTML5下不同于http的一种新协议(本质上也是基于tcp协议),实现了浏览器和服务器的全双工通信,是一个持久化的协议
-
WebSocket是一种双向通信协议。在建立连接后,WebSocket服务器端和客户端都能主动向对方发送或接收数据,就像Socket一样;
-
WebSocket需要像TCP一样,先建立连接,连接成功后才能相互通信。
原理:
websocket为应用层协议,其定义在TCP/IP协议栈之上通过握手机制,在客户端和服务器之间建立了一个类似TCP的长连接,从而方便他们之间的双向通信
数据收发的三个过程
1)TCP协议的三次握手四次挥手的过程必然存在 2)websocket协议本身的握手环节
3)websocket协议握手成功之后的收发数据环节
webSocket和http协议的区别:
相同点:1、都是基于tcp的可靠性传输协议
2、都属于应用层协议
不同点:1、webSocket是双向通信协议,模拟Socket协议,可以双向发送或者接受信息,而HTTP是单向的。
2、webSocket是需要浏览器和服务器握手建立连接的
3、http是由浏览器发起向服务器的连接,服务器预先并不知道这个连接。
两者联系:webSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协 议的。
webSocket发送数据的总体过程
1、首先,客户端发起HTTP请求,经过TCP的三次握手后,建立TCP连接;在HTTP请求中存放WebSocket支持的版本信息等,如:Upgrade,connection,webSocket-Version等
2、服务器在收到客户端握手的信息请求后,同样产用HTTP协议回馈数据
3、最后,客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信
注意:
最初握手阶段是http协议,握手完成后就切换到了webSocket协议,并完全与http协议脱离了
建立通讯时,是由客户端主动发起连接请求的,服务端被动监听。
webSocket出现的价值
http----------------long poll(长轮询)-----------Ajax轮询(短轮询)-------------webSocket
1、http
http是一种无状态协议,每当一次会话完成后,服务端都不知道下一次的客户端时谁,需要每次知道对面时谁,才进行相应的响应,有较大的沟通障碍
http协议产用一次一次请求,一次响应,每次请求和响应都携带大量的header头,对于实时通讯来讲,解析请求头也需要时间,效率低下
只能一收一发,也就是说客户端发请求,服务端返回数据,不能实现主动收发。
2、long poll
对于http带来的问题,出现了第一个解决的方法--长轮询
简单说,当客户端想服务端发送请求时,如果服务端的数据没有进行变更,那么请求会停在那,知道服务端的数据发生了变更,或者等到一定时间超时才会返回。返回后,客户端又会立即再次发起下一次的长轮询。
优点事解决了http不能实时更新的弊端,但是因为这个事件很短,发请请求即处理请求返回响应,实现了(伪长连接)
总体来说:
-
推送延迟。服务端数据发生变更后,长轮询结束,立刻返回响应给客户端。
-
服务端压力。长轮询的间隔期一般很长,例如 30s、60s,并且服务端 hold 住连接不会消耗太多服务端资源。
-
花婕取快递的例子,花婕今天一定要取到快递,他就一直站在快递点,等待快递一到,立马取走
从例子上来看有个问题: 假如有好多人一起在快递站等快递,那么这个地方是否足够大,(抽象解释:需要有很高的并发,同时有很多请求等待在这里)
3、Ajax轮询
基于http的特性,简单讲就是规定每隔一段时间就由客户端发起一次请求,查询有没有新消息,如果有,就返回。没有的话就等待相同的事件间隔再次查询
优点是解决了http不能实时更新的弊端,因为这个时间很短,发请请求即处理请求返回响应,把这个过程放大N倍之后,相当于request===response
eg:举个形象的例子(假设花婕今天有个快递快到了,但是花婕忍耐不住,就每隔十分钟给快递员或者快递站打电话,询问快递到了没,每次快递员就说还没到,等到下午花婕的快递到了,but,快递员不知道哪个电话是花婕的,(可不是只有花婕打电话,还有郝晓建,梁鹏宇),所以只能等花婕打电话,才能通知他,你的快递到了)
从例子上来看有两个问题: 1、假如说,花婕打电话的时间间隔为10分钟,当他收到快递前最后一次打电话,快递员说没到,他刚挂掉电话,快递入库了(就是到了),那么等下一次时间到了,花婕打电话知道快递到了,那么这样的通讯算不算实时通讯?很显然,不算,中间有十分钟的时间差,还不算给快递员打电话的等待时间(抽象的解释:每次request的请求时间间隔等同于十分钟,请求解析相当于等待) 2、假如说花婕所在的小区每天要收很多快递,每个人都采取主动给快递员打电话的方式,那么快递员需要以多快的速度接到,其他人打电话占线也是问题(抽象解释:请求过多,服务端响应也会变慢)
总体来说,Ajax轮询存在的问题
1、推送延迟
2、服务端压力,配置一般不会变化,频繁的轮询会给服务端造成很大的压力
3、推送延迟和服务端塔里无法中和。降低轮询的间隔,延迟降低,压力倍增;增加轮询的间隔,压力降低,延迟增高
4、webSocket
一但webSocket建立连接之后,后续数据都是以帧序列的形式传输。在客户端断开webSocket连接或Server端中断连接前,不需要客户端和服务端发起连接请求。在海量并发及客户端和服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接收消息在同一个持久连接上发起,实现了真长连接,实时性能明显。
eg:
假如说,花婕去快递站拿快递,去了之后,快递员说没到,花婕说:麻烦我快递到的时候推送给我噢,快递员说:好的好的 注意:只能由客户端去发起请求建立连接,也就是只能先由花婕去快递站跟快递员说明,我们留个联系方式吧,有快递你告诉我一下。
WebSocket有以下特点:
是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而HTTP长连接基于HTTP,是传统的客户端对服务器发起请求的模式。 HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据,这显然和原有的HTTP协议有区别所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5)
webSocket基本应用
1、创建对象
ws = new WebSocket('ws://localhost:9998') //'ws://localhost:9998' 为 服务端的路径
2、监听事件
①连接成功事件
ws.onopen = () => {
console.log('连接服务端成功了...')
ws.send('你好,我是花婕'); //发送数据
}
②接收数据事件
ws.onmessage = msg => {
console.log('接收到从服务端发送过来的数据了')
console.log(msg)
recv.innerHTML = msg.data
}
③关闭连接事件
ws.onclose = () => {
console.log('连接服务器失败')
send.disabled = true //发送数据按钮启用
}
重连机制
一般断线时都会触发websocket的onclose方法,因此,只需在此方法中重新发起一个websocket连接即可
ws.onclose = function (event) {
// 10秒后重新连接,实际效果:每10秒重连一次,直到连接成功
setTimeout(function () {
socketInit() // 重新调用连接webSocket事件
}, 10000);
};
webSocket心跳保活
websocket长连接有默认的超时时间(1分钟),也就是说,超过一定的时间客户端和服务器之间没有发生任何消息传输,连接会自动断开;除此之外,服务器或防火墙一般也会在一段时间不活动并超时之后终止外部的长连接。因此,若需要使客户端一直保持连接,就需要设置心跳保活机制了。
const checkTimer = useRef<NodeJS.Timeout>();
//心跳保活
checkTimer.current = setInterval(() => { //每隔五秒钟发送一次心跳
socket?.current?.send('links');
}, 5000);
webSocket前端主动断开的方法
ws = new WebSocket('ws://localhost:9998')
ws.close();
webSocket里面添加Token参数的方法
1、send发送参数
var ws = new WebSocket("ws://" + url + "/webSocketServer");
ws.onopen=function(){
ws.send(token)
2、请求地址中携带参数
var ws = new WebSocket("ws://" + url?token + "/webSocketServer");
var wss = new WebSocket("wss://" + url?token + "/webSocketServer");
3、基于协议头
websocket请求头中可以包含Sec-WebSocket-Protocol这个属性,该属性是一个自定义的子协议。它从客户端发送到服务器并返回从服务器到客户端确认子协议。我们可以利用这个属性添加token。
var ws = new WebSocket("ws://" + url+ "/webSocketServer",[token]);