WebSocket 的出现使得浏览器提供对 Socket 的支持成为可能,从而在浏览器和服务器之间提供了一个基于 TCP 连接的双向通道。Web 开发人员可以非常方便地使用 WebSocket 构建实时 web 应用。
Web 应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS 订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。所以保持客户端和服务器端的信息同步是实时 Web 应用的关键要素,对 Web 开发人员来说也是一个难题。
HTML5 WebSocket 设计出来的目的就是要取代轮询和 Comet 技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
server
开启node服务,实现ws服务端:
const WebSocketServer = require('ws').Server
// 创建websocket服务器
const wss = new WebSocketServer({ port: 8888 })
// 注册连接开启事件,同时其他事件的初始化
wss.on('connection', function (ws) {
console.log('ws client connected')
//接收客户端发送的报文事件
ws.on('message', function (data) {
console.log(`接收数据:${data}`)
ws.send(JSON.stringify(new Date().getTime()))
})
// 注册连接关闭事件
ws.on('close', function (message) {
console.log(message)
})
})
console.log('websocket server running at ws://127.0.0.1:8888/')
client
api 定义websocket socket.ts
const wsConnection: any = {
websock: null,
wsurl: 'ws://127.0.0.1:8888/',
timeout: 10 * 1000,
timeoutObj: null,
callback: null,
initWebSocket: function() {
this.websock = new WebSocket(this.wsurl)
this.websock.onopen = this.wsOpen
this.websock.onmessage = this.wsMessage
this.websock.onclose = this.wsClose
this.websock.onerror = this.wsError
},
wsOpen() { // scoket已连接,开始心跳
wsConnection.startHeartbeat()
},
wsMessage: function(msg: any) { // 接收到数据重新开始心跳
wsConnection.startHeartbeat()
wsConnection.callback(msg)
},
wsClose: function() {
console.log(`断开连接`)
},
wsError: function() {
wsConnection.timeoutObj && clearInterval(wsConnection.timeoutObj)
wsConnection.initWebSocket()
console.log('error')
},
startHeartbeat() {
this.timeoutObj && clearInterval(this.timeoutObj)
this.timeoutObj = setInterval(() => {
if(this.websock.readyState !== 1) { // 判断websock当前状态
this.initWebSocket()
}else {
let heartbeat = JSON.stringify(new Date().getTime())
this.websock.send(heartbeat)
}
}, this.timeout)
}
}
export default wsConnection
使用 - hello.vue
...
import wsConnection from '../api/socket'
...
callback(msg: any) {
console.log('mmmmmm',msg)
}
mounted(): void {
wsConnection.initWebSocket()
wsConnection.callback = this.callback
}
destroyed() {
wsConnection.websock.close()
}