http vs websocket
通信
串行通信中,数据通常是在俩个终端之间进行传送,根据数据流的传输方向分为以下三种基本传送方式:单工、半双工和全双工。
基本区别为:
单工
:单工通信只有一根数据线,通信只在一个方向上进行,这种方式的应用实例有:监视器、打印机、电视机等。半双工
:半双工通信也只有一根数据线,它也单工的区别是这根数据线既可作发送又可作发接收,虽然数据可在两个方向上传送,但通信双方不能同时收发数据。http协议采用的就是这个通信方式全双工
: 数据的发送和接收用两根不同的数据线,通信双方在同一时刻都能进行发送和接收,这一工作方式称为全双工通信。在这种方式下,通信双方都有发送器和接收器,发送和接收可同时进行,没有时间延迟。websocket采用的就是这个通信方式
http
- http协议主要关注的是 客户端——>服务器(获取资源)
特点:无状态协议;
每个请求都是独立的;
请求应答模式,服务器无法主动给客户端推送消息(单工,半双工,全双工)
http受浏览器同源策略的影响
websocket
双向通信(全双工协议)每次不需要重新建立连接,可以一直相互通信
不使用websocket 以前的双向通信的实现方式
Comet,主要是为了是实现服务端可以像客户端桶送数据,为了继绝实时性比较高的情况。
- 1.轮询(客户端定期向服务端发送请求采用方式,前端setInterval定时器发送请求)
轮询会在的问题:- 轮询方式会存在竞速问题,无法保证请求的先后顺序,可能会存在多个请求返回的结果同时修改资源。
- 频繁的网络请求 会导致服务器负荷增加 同时频繁的客户端发请求也会影响客户端性能问题
- http 发送的时候 会增加http报文(headers、鉴权、内容类型) 会出现额外的数据消耗
- 实时性比较低 定时轮询前端定时轮询(定时器发请求)无法处理即时处理的请求
轮询的优点 - 容易实现
- 不适合实时性比较高的,低并发
- 2.长轮询(前端接口递归调用)
想解决短轮询的缺点(想将实时性更强)
长轮询存在的问题- 实时性强了,同时也造成了更多的网络请求
- 链接堆积问题,链接需要在服务端中保持打开,占有服务器资源(前端需要大量数据从服务端访问,会一直从服务端获取)
优点 - 实时性强了,但是要求服务端的并发能力要强
- 3.iframe流(使用ifream存在的沙箱模式)
存在的问题- 单通信(服务端直接推送客户端消息)
优点 - 具有实时性,且不需要客户端和服务端频繁发请求
- 单通信(服务端直接推送客户端消息)
4.sse EventSource(html提供的,单项通信,客户端可以监控服务端推送的事件。只能推送文本消息,适合小数据)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 服务端代码
app.get('/clock',function(res,req){
// 这里表明服务器传递的是时间流
res.setHeader('Content-Type','text/event-stream');
setInterval(()=>{
// 和http协议一样,按照行的方式传输
// Content-Type:xxx
// Authorization:xxx
res.write(`data:hello\n\n`)
},1000)
})
// 客户端代码 script中
const eventsource = new EventSource('xxx接口地址')
eventsource.onopen = function(){
console.log('Connection opened');
}
// 发送消息
eventsource.onmessage = function(e){
console.log(e.data)
}
存在的问题
- 单项传输,客户端无法给服务端传递数据- 5.webSocket(h5提供的api)
优点双向通信
持久连接
发送的消息增加帧是非常小的
支持多种数据格式
天生支持跨域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35// 客户端代码
const ws = new Websocket('ws://loacalhost:3000')
ws.onopen = function(){
console.log('Content opened')
ws.send('hello Serve')
}
ws.onmessage = function(e){
console.log('服务器响应数据:'+ e.data)
}
// 服务端代码
import express from 'express'
import http from 'http'// webSocket首先基于http协议
import { WebSocket } from 'ws'
const wsServer = new WebSocket({ server })
wsServer.on('connection',(ws)=>{
console.log('Connection opend')
// 给客户端发送消息
ws.send('hellow client')
ws.on('message',(message)=>{
console.log('客户端发送的数据:' + message)
})
})
server.listen(3000)拓展:
协议的表示方式?以http为例子
就是要了解http各种header的使用
怎么实现握手的,数据长什么样子,怎么通信查看网络得知:
webSocket协议请求行显示:请求方式 GET ws://localhost:3000 协议版本 HTTP/1.1
Connection : Upgrade
Upgrade: websocket 升级的协议是什么
Sec-Websocket-Version: 13 协议的版本
生成Sec-Websocket-Key:用于生成唯一的,保证安全的websocket连接 防止恶意连接 可以用于握手
Sec-Websocket-Accept 是根据key算出来的 表示握手成功
通过wireshark工具可以抓包,了解
会生成key->·GBUN9IA5TYXPYgQehlxEUw== 握手的时候创建一个随机的key
accept-> TpUkC2LowejLbA6ZRgwSL8Rk4FI= 服务端要响应一个值每一次的key都不一样,采用以下方法创建安全的握手连接
1
2
3
4
5
6
7// 加密库
import crypto from 'crypto'
const number = '258EAFA5-E914-47DA-95CA-C5ABODC85B11const'; const websocketKey ='GBIN9IA5TYXPYgQehlxEUw=='
// 采用hah算法生成更新生成摘要输出base64格式 响应给客户端
const websocketAccept = crypto.createHash( 'sha1' ).update(websocketKey + number).digest( 'base64' )完整的握手过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48// 服务端代码
import net from 'net'// 可以接受原始的消息
// 每个人连接都会产生一个socket
const server = net.createServer(function(socket){
// 客户端发消息 先握手
socket.once('data',function(data){
// 发送的报文 data
/**
* data包含
GET / HTIP/1.1 *请求行*
Host: localhost:3000
Connection: UpgradePragma: no-cacheCache Control: no-cacheUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac 0S X 10 15 7) AppleWebKit/537.36 (KHTMLlike Gecko) Chrome/115.0.0.0 Safari/537.36Upgrade: websocket
0rigin: http://127.0.0.1:5500
Sec WebSocket-Version: 13
Accept-Encoding: gzip,deflate,brAccept-Language: zh-CN, zh;g=0.9Sec-WebSocket-Key: LFD4X3DrVLhObMnKL0b5K0
Sec-WebSocket-Extensions: permessage-deflate; client max window bits
*/
data = data.toString()
// 说明要升级成websocket协议 再报文中读取是否已经是websocket协议
if(data.match(/Upgrade:websocket/)){
/**
* 在抓包工具中读取到 key用来解析 ***在报文中都是字符串存在的***
Host; localhost:3000\r\n
Connection: Upgrade rn
Pragma: no-cache rin
Cache Control: nocache\rin
User-Agent; Mozilla/5.0 (Macintosh; Intel Mac 05 X 10 15 7) AppleWebkit/537,36 (KHTML, like Gecko
Upgrade: websocket r\n
0rigin: http://127.0.0.1:5500\r\n
Sec-WebSocket-Version: 13r'nAccept-Encoding: gzip, deflate, bririnAccept-Language: zh-CN zh;a=0.9\r\n
Sec-WebSocket-Key:P2P2F9kEf/wg18RkzXM8eA==\rin
Sec-WebSocket-Extensions: permessage-deflate; client max window bits'rinrin
*/
let rows = data.split('\r\n')
console.log(rows)
/**
* rows 打印得出
GETHTTP/1.1Host: localhost:3000'Connection: Uggrade'Pragma; no-cache'Cache-Control; no-cache'"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac 0S X 10 15 7) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/115.0.0.0 Safari/537.36''Uparade: websocket'
*/
}
})
})
server.listen(3000,function(){
console.log('server start port 3000')
})
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ayozooZ!