WebSocket原理
1.双向
2.高效
socket.io
- 服务端
socket.on('connection', function(){});
socket.on('disconnect', function(){}); - 客户端
socket.on('connect', function(){});
socket.on('disconnect', function(){});
原生WebSocket
- WebSocket 是前台的东西,是Html5自带的,后台只有Socket
握手连接数据
GET / HTTP/1.1
Host: localhost:8080
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: io=1xmCQieVn0lSrrN-AAAA
Sec-WebSocket-Key: XOP3MFdA3K93Uo8EPd8g9Q==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
处理连接数据
1.第一行 (请求行) 删掉
GET / HTTP/1.1
2.每行数据用": "切开
let lines = str.split('\r\n');
3.舍弃第一行(请求头),最后两行(空的)
`lines = lines.slice(1, lines.length - 2);`
4.切开(所有数据转换成 key value 保存 )
let headers={};
lines.forEach((line=>{
let [key, val] = line.split(': ');
headers[key.toLowerCase()] = val;
}))
5.判断服务类型, 对比socket版本, 将处理信息放到消息头里返回给客户端 (完成握手过程)
if(headers[`upgrade`] != `websocket`){
console.log('其他协议', headers[`upgrade`]);
//如果不是websocket 协议,直接关闭连接
sock.end();
}
else if(headers[`sec-websocket-version`] != 13){
console.log('版本不对', headers[`sec-websocket-version`]);
//版本不对
sock.end();
}
else{
let key=headers[`sec-websocket-key`];
let mask = `258EAFA5-E914-47DA-95CA-C5AB0DC85B11`;
// sha1(key+mask) -> base64 ==> client 转换成base64的格式发送给客户端 完成协议升级
let hash = crypto.createHash('sha1');
hash.update(key + mask);
let key2 = hash.digest('base64');
// console.log(key2);
//101状态码 switching protocols 切换协议类型, 协议升级
sock.write(`Http/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${key2}\r\n\r\n`); //\r\n http协议标准分行,所以要加
//连接成功 就不需要断开了
// sock.end();
//握手结束
console.log('hand shake end...');
//真正的数据
sock.on('data', data=>{
console.log('有数据了');
//data 获取到的是一个数据帧
})
}
-
数据帧
image
1.FIN 是否最后一帧(1 bit)
2.RSV1、RSV2、RSV3 预留位
3.opcode 帧类型
4.MASK 掩码,是否加密数据,默认必须置为 1(WebSocket设计必须是加密的所以这里一定为1)
5.Payload len 数据长度(内容的长度,单位字节)
6.Extended Payload length 扩展的内容长度
使用WebSocket
- socket.io库
- 原生WebWocket
1.net模块
2.流程
3.握手
--- C:version:13、sec-websocket-key:xxxxxx、
--- S:101 Swiching Protocols 切换协议、sec-websocket-accept :base64 (sha1(mask+sec-websocket-key)=>base64 返还给客户端)
--- 握手完成,客户端服务器双向通讯
事件:
Client:
onopen
onmessage
onclose
Server:
sock.once('data', 握手)
sock.on('data', 其他数据请求)
sock.on('end', 连接断开)
4.数据帧解析(解包)