什么是Websocket
WebSocket是一种通信协议,可在单个TCP连接上进行全双工通信。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。
Websocket是一种通信协议,与HTTP不同,HTTP只能实现单项通信,也就是客户端请求服务端,而Websocket是双向数据通信即能使客户端请求服务端又能使服务端推送数据到客户端。
特点:
为什么要使用Websocket
就前面的概念和特点就已经有充足的理由让我们使用Websocket,不过他最大的特性是支持长连接,客户端与服务端双向通信,这种特性的好处实在太大了,先来看一个需求
每隔一段时间显示后台给的最新数据,如果没有Websocket我们会用ajax来做,但是HTTP协议是单项通信,请求一次就没了,为了保持数据的更新我们每隔一段时间就要请求服务器或许几秒几分钟,因此我们会给ajax添加一个定时器
setInterval(()=>{
$.ajax({
url: 'http://localhost:8080',
dataType:'text',
type:'GET',
success:function(data){
console.log(data)
}
})
},1000)
但是这样的坏处在于隔一段时间就要请求服务器很浪费资源也给服务器带来了很大的压力。
而websocket就很好的解决了这个问题
Websocket协议
部分请求头
Connection: Upgrade
Host: localhost:8080
Origin: file://
Pragma: no-cache
Sec-WebSocket-Key: infTM/NWqL6ded8db1onXg==
Sec-WebSocket-Version: 13
Upgrade: websocket
其中Connection:Upgrade
和Upgrade: websocket
表示协议将要升级为websocket连接
Sec-WebSocket-Key
标识连接
Sec-WebSocket-Version
表示协议的版本
服务端返回请求头
Connection: Upgrade
Sec-WebSocket-Accept: +bCqQLLmSn0zlNbbOdgyKO1FjUg=
Sec-WebSocket-Extensions: permessage-deflate
Upgrade: websocket
建立连接
状态101表示连接的HTTP协议将被更改
type为websocket
time : pending表示客户端与服务器一直保持连接。
Node.js原生socket
const http = require('http');
const net = require('net')
let server = net.createServer((sock=>{
sock.once('data',buffer=>{
//第一次握手
let str = buffer.toString();
console.log(str)
})
sock.on('end',function(){
console.log('端口')
})
}))
server.listen(8080)
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
</head>
<body>
</body>
<script>
let ws = new WebSocket('ws://localhost:8080/')
ws.onopen=function(){
alert('连接建立')
}
ws.onmessage=function(){}
ws.onclose=function(){}
</script>
</html>
请求信息打印如下
GET / HTTP/1.1
Host: localhost:8080
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Mobile Safari/537.36
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Sec-WebSocket-Key: lgTItWtSBX/NTNSIYNcueQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
此时浏览器并没有打印“连接建立”因为客户端与服务器还没有完成握手
Node.js原生实现socket第一次握手
const http = require('http');
const net = require('net');//创建原始服务器
const crypto = require('crypto');
//过滤请求头
function parseHeader(str){
let arr = str.split('\r\n').filter(line=>line)
arr.shift();
// console.log(arr)
let headers = {}
arr.forEach(line => {
let [name,value] = line.split(':')
name = name.replace(/^\s+|\s+$/g,'').toLowerCase();
value = value.replace(/^\s+|\s+$/g,'');
headers[name] = value;
});
return headers;
}
let server = net.createServer((sock=>{
sock.once('data',buffer=>{
//第一次握手
let str = buffer.toString();
let headers = parseHeader(str)
console.log(headers)
if(headers['upgrade']!='websocket'){
//判断协议是否升级
console.log('no upgrade')
sock.end()
}else if(headers['sec-websocket-version']!='13'){
//判断协议版本是否等于13
console.log('no 13')
sock.end()
}else{
//判断key
// key=>http头
// uuid=>'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
// 将key和uuid做连接然后接收sha1在进行base64返回给客户端
let key = headers['sec-websocket-key']
let uuid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
let hash = crypto.createHash('sha1');
hash.update(key+uuid);
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`)
}
})
sock.on('end',function(){
console.log('端口')
})
}))
server.listen(8080)
浏览器正常打印“连接建立”连接成功
JS中使用websocket
常用事件
let ws = new WebSocket(‘ws://localhost:8080/’);//创建一个websocket
WebSocket.onopen: 连接成功后的回调
WebSocket.onclose: 连接正常关闭后的回调
WebSocket.onerror: 连接失败后的回调
WebSocket.onmessage: 客户端接收到服务端数据的回调
webSocket.bufferedAmount: 未发送至服务器的二进制字节数
WebSocket.binaryType: 使用二进制的数据类型连接
WebSocket.protocol : 服务器选择的下属协议
WebSocket.url : WebSocket 的绝对路径
WebSocket.readyState: 当前连接状态,对应的四个常量
常用方法
WebSocket.close() 关闭当前连接
WebSocket.send(data) 向服务器发送数据
使用socket.io建立连接
nodejs
//nodejs
const http = require('http');
const io = require('socket.io');
//
let server = http.createServer((req,res)=>{
}).listen(8080);
//建立websocket连接
let wsServer=io.listen(server);//监听http如果有websocket连接转交websocket
wsServer.on('connection',sock=>{
sock.emit('name','数据');//向客户端发送数据
sock.on('name',function(datas){
//接收客户端数据
console.log(datas);//12
})
})
//前台js
let sock = io.connect('ws://localhost:8080/');
sock.emit('name',12);//发送数据
sock.on('name',name=>{
//接收服务端数据
console.log(name);//数据
})