顺晟科技
2021-08-21 11:00:58
358
WebSocket 是一个持久化的协议,通过次 HTTP Request 建立连接之后,再把通信协议升级成 websocket,保持连接状态,后续的数据交换不需要再重复请求。websocket 可以看成一种类似 TCP/IP 的 socke t技术,在 web 应用中实现、并获得同 TCP/IP 通信一样的双向通信功能,因此客户端既和服务器可以发送消息也可以接收消息,同时还支持多路复用的功能,由于它借用了 HTTP 协议的一些概念,所以被称为 WebSocket。
webSocket API定义了web应用和服务器进行通信的公共接口,具体的构造函数创建对象、对象的属性、方法、事件及它的意义,在上一篇《HTML5(十一)——WebSocket 基础教程》文章中已详细介绍。
WebSocket 协议可分为两部分:握手阶段和数据通信阶段。
WebSocket 为应用层协议,定义在 TCP/IP 协议栈之上,连接服务器的 url 是以 ws 或 wss 开头的。ws 开头的默认TCP端口为80,wss 开头的默认端口为443。
ws(websocket)是不安全的,容易被窃听,只要别人知道你的ip和端口号,任何人都可以去连接通讯。
wss(web socket secure)是websocket的加密版本。
客户端去与服务器建立 TCP 连接,客户端生成 websocket 对象,然后使用 API 建立连接,代码如下:
let ws= new WebSocket('ws://localhost:8888') ws.onopen = function(){ console.log("连接") }
客户端与服务器建立连接之后,客户端发送握手请求,随后服务器发送握手响应即完成握手阶段。
客户端握手请求如下:
'GET / HTTP/1.1',
'Host: localhost:8888',
'Connection: Upgrade',
'Pragma: no-cache',
'Cache-Control: no-cache',
'Upgrade: websocket',
'Origin: file://',
'Sec-WebSocket-Version: 13',
'Accept-Encoding: gzip, deflate, br',
'Accept-Language: zh-CN,zh;q=0.9',
'Sec-WebSocket-Key: In1aAp/ya9Lkv+tsUtXLXQ==',
'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits',
服务器握手响应如下:
Status Code: 101 Switching Protocols
Connection: Upgrade
sec-websocket-Accept: HBMDBbZMiS59r3aAITpGtJ64Mfc=
Upgrade: websocket
WebSocket 握手连接成功之后。可以使用 send 进行发送数据,onmessage 接收数据,如下发送“你好”:
let ws= new WebSocket('ws://localhost:8888') ws.onopen = function(){ console.log("连接成功") ws.send("你好") } ws.onmessage = function(res){ console.log('接收到的消息',res) }
服务器打印接收到的数据,如:<Buffer 81 86 af 87 53 b4 4b 3a f3 51 0a 3a>。
websocket 在发送数据时,被组织为一串数据帧,然后进行发送。传送的帧包含两部分:数据帧和控制帧。数据帧可以携带文本数据或者二进制数据,控制帧包含关闭帧和 Ping/Pong 帧。
把接收到的buffer十六进制数据转成二进制数据,控制帧与上述各个类型帧进行对比解析其意义。
任何一端可以关闭连接。客户端关闭连接如下:
ws.close()
然后发送关闭帧给对方,通常会带有关闭连接的状态码,常见的状态码如下:
3.1、客户端创建websocket对象,并建立连接之后发送数据。其中 ws 地址根据后台服务端口对应。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let ws= new WebSocket('ws://localhost:8888') ws.onopen = function(){ console.log("连接") ws.send("你好") } ws.onmessage = function(res){ console.log('res',res) } </script> </body> </html>
3.2、使用 node.js 创建一个 websocket 服务,如创建一个serve.js文件,代码如下:
const http = require("http") const net = require("net") //原生的websocket const crypto = require('crypto') // 安全性校验 let serve = net.createServer(sock=>{ //只握手一次 sock.once('data',(data)=>{ console.log("hand shake start") // 开始握手 let str = data.toString(); let lines = str.split('\r\n') //舍弃行和最后两行 lines = lines.slice(1,lines.length-2) let headers = {} lines.forEach(line=>{ let [key,val] = line.split(': ') headers[key.toLowerCase()] = val }) if( headers['upgrade']!= 'websocket' ){ console.log("其他协议") sock.end() }else if(headers['sec-websocket-version']!=13){ console.log("版本不对") sock.end() }else{ let key = headers['sec-websocket-key'] let mask = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' //sha1(key+mask) -> base64 =>client let hash = crypto.createHash('sha1') hash.update(key+mask) let key2 = hash.digest('base64') sock.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade:websocket\r\nConnection:Upgrade\r\nsec-websocket-Accept:${key2}\r\n\r\n` ) console.log("hand shake end") // 握手结束 //真正的数据 sock.on('data',res=>{ console.log("真正接收数据",res) //数据解析 let FIN = res[0]&0x001; let opcode = data[0]&0x0F0; let msak = data[1]&0x001; let payload = data[1]&0x0FE; }) } }) //断开 sock.on('end',()=>{ console.log("连接已断开") }) }) serve.listen("8888")
使用命令 node serve.js 或node serve 启动服务,服务启动成功之后可以使用localhost:8888访问服务。
启动服务之后,访问前边创建的html文件访问websocket服务。
06
2022-10
15
2022-09
15
2022-09
08
2021-09
31
2021-08
21
2021-08