websocket总结
目录websocket介绍http与websocket注意websocket请求格式对比http协议请求格式异同点websocket响应格式注意基于node.js的websocket模块ws模块服务端客户端 socket.io模块服务端 客户端WebSocket是一种网络通信协议,是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。RFC6455定义了它的通信标准。为什么websoc
目录
客户端sec-websocket-key和服务端sec-websocket-accept的关系
WebSocket协议
前言
HTTP通信只能由客户端发起,所以早期很多网站为了实现推送技术,所用的技术都是轮询;轮询是指由浏览器每隔一段时间(如每秒)向服务器发起HTTP请求,然后服务器返回最新的数据给客户端,为了能更好的节省服务器资源和带宽,并且能够更实时的进行通讯,HTML5规范中出现了WebSocket协议
含义:WebSocket是一种网络通信协议,是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。RFC6455定义了它的通信标准。
HTTP与WebSocket
- HTTP协议是一种典型的客户端请求,服务端响应的协议(服务端永远不会直接给客户端消息,除非客户端请求)
- websocket的全双工(Full Duplex)的通讯传输允许数据在两个方向上同时传输,任何一方都可以主动的发消息给对方。
注意
- websocket连接必须由浏览器发起,因为请求协议是一个标准的http协议
- websocket使用80(ws://)、(wss://)端口,可以绕过大多数防火墙的限制
- websocket需要先建立连接,这就使得websocket成为一种有状态的协议,之后通信时可以省略部分的状态信息
- websocket并不是全新的协议,而是利用了http协议来建立连接(也叫做握手,Handshake)
WebSocket的应用场景:社交订阅、股票基金报价、体育实况更新、多媒体聊天、多玩家游戏等
为什么websocket连接可以实现全双工通信http连接不可以
http协议是建立在TCP协议之上的,TCP协议本身就有全双工通信,但http协议的请求应答机制限制了全双工通信。websocket连接建立以后,其实只是简单的规定了一下通信不使用http协议了,直接互相发数据就可以。
websocket请求格式
对比http协议请求格式异同点
- 请求地址不是类似/path/,而是以ws://开头的地址
- 请求头connection:upgrade(表示客户端希望连接升级)
- 请求头upgrade:websocket(表示这个连接将被转化为websocket连接)
- sec-websocket-key:客户端随机生成的字符串,其用于标识这个连接,并非用于加密数据
- sec-websocket-version:指定了websocket的版本号
websocket响应格式
客户端sec-websocket-key和服务端sec-websocket-accept的关系
以dghliHNhbXBsZSBub25jZQ==为例:
服务器收到客户端sec-websocket-key后会进行以下操作
- sec-websocket-key加上一个固定的GUID值(258EAFA5-E4-47DA-95CA-C5AB0DC85B11)——dghliHNhbXBsZSBub25jZQ==258EAFA5-E4-47DA-95CA-C5AB0DC85B11
- 将1的结果进行SHA-1摘要计算:b37a4f2cc0624f1690f64606cf385945b2bec4ea
- 将2的结果进行Hex to base64编码:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
- 将3的结果作为sec-websocket-accept响应头1的值,返回给客户端
如此操作,可以尽量避免普通的HTTP请求被误认为websocket协议
注意
- 上面的响应码101表示本次连接的http协议即将被更改,更改后的协议就是upgrade:websocket指定的websocket协议
- 版本号和子协议规定了双方都能理解的数据格式,以及是否支持压缩等等,如果仅用websocket的API则不需要关心这些
- 一个websocket连接就建立成功,浏览器和服务器可以随时的主动发送消息给对方。消息有2种,一种是文本,一种是二进制数据,通常,我们可以发送JSON格式的文本,这样在浏览器处理起来就十分容易
- 安全的websocket连接机制和https类似。首先,浏览器用wss://xxx创建websocket连接时,会先通过https创建安全的连接,然后,该https连接升级为websocket连接,底层通信走的依然是安全的SSL/TLS协议
- websocket协议对于有一些低版本的浏览器可能不支持
基于node.js的websocket模块
- ws模块
- socket.io模块
ws模块
npm初始化:npm init
安装ws模块:npm i ws
常用场景:一个服务端服务于多个客户端
服务端
const express=require("express")
const app=express()
app.use(express.static("./public"))
//http响应
app.get("/",(req,res)=>{
res.send({ok:1})
})
app.listen(5000)
//websocket响应
const {WebSocket}=require("ws")
const wss=new WebSocket.WebSocketServer({port:8080})
wss.on('connection',function connection(ws){
ws.on('message',function message(data){
console.log("收到:%s",data);
//转发给其他人
wss.clients.forEach(function each(client){
if(client!==ws&&client.readyState===WebSocket.OPEN){
client.send(data,{binary:false})
}
})
})
ws.send('欢迎来到聊天室')
//当有客户端断开连接时触发
ws.on("close",()=>{
console.log("帅哥走了");
})
})
客户端
//chat.html文件内
<body>
<h1>聊天室客户端</h1>
</body>
<script>
//创建websocket连接
var ws=new WebSocket("ws://localhost:8080")
//打开连接成功后走的回调函数
ws.onopen=function(){
console.log("连接成功");
//发送消息
ws.send("hello world")
}
//每次服务端发消息时触发的回调函数
ws.onmessage=function(msgObj){
console.log(msgObj.data);
}
//连接失败时走onerror回调函数
ws.onerror=function(){
console.log("连接失败");
}
//服务器宕机时走的回调函数
ws.onclose=function(){
console.log("服务器宕机");
}
</script>
注意:静态文件夹为public,里面有chat.html页面
socket.io模块
npm初始化:npm init
安装socket.io模块:npm i socket.io
服务端
//服务端
const http=require("http")
const fs=require("fs")
const app=http.createServer()
app.on("request",(req,res)=>{
fs.readFile(__dirname+"/index.html",function(err,data){
if(err){
res.writeHead(500)
return res.end("Error loading index.html")
}
res.writeHead(200)
res.end(data)
})
})
app.listen(3000,()=>{
console.log("server start");
})
//下面引入代码必须在app监听完端口的后面
const io=require("socket.io")(app)
//监听了用户连接的事件,只要用户连接,便会触发该事件
//socket表示用户的连接,socket.emit表示触发某个事件,socket.on表示监听某个事件
io.on("connection",socket=>{
console.log("新用户连接了");
//socket.emit的方法应该用于给浏览器发送数据
//参数1:事件名字-名字随意写
//服务器发送数据给客户端
socket.emit("get",{name:"cjc"})
//服务器从客户端接收数据
socket.on("send",data=>{
console.log(data);
})
})
客户端
引入socket.io.js文件:<script src="/socket.io/socket.io.js"></script>
<!-- index.html页面内 -->
<body>
<script src="/socket.io/socket.io.js"></script>
<h1>node.js聊天室</h1>
<script>
//连接socket服务,参数为服务器地址
var socket=io("http://localhost:3000")
//接收服务器返回的数据
socket.on("get",data=>{
console.log(data);
})
//向服务器发送数据
socket.emit("send","我想发送数据")
</script>
</body>
注意:
- socket.io有用到websocket协议,但是对于不支持websocket的浏览器会回退到http的轮询,而且提供自动重连,而ws就没有此支持
- socket.io模块的数据传输对象和字符串都可以,ws模块数据传输只能为字符串
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)