文章目录
WebSocket是什么?
-
websocket 是 html5 中出的一个协议 ,它跟我们的http协议是一种交集的关系,可以理解成它在http协议上又补充了很多东西(http是无状态协议,连接一次断开后并不会记录), 它可以帮我们实现及时的通讯。 – 应用 聊天app 等。
-
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
-
我们的http协议(也就是我们平常发送的请求)我们一个请求只能有一个响应(res),而且我们的响应都是被动动(只有我们主动发请求才会有响应),我们的服务器并不能主动向我们的客户端发送信息。
ajax轮询 和 long poll 长轮询
大家知道了我们的html5是近些年推出的,那在以前的时候我们想实现上面那种情况该怎么办?
- ajax轮询的方式 就是我们每隔几秒钟就向服务器发一次请求,询问服务器是否有新的信息。
- long poll也是采用轮询的方式,它采用的是阻塞模型,我们客户端发起一个请求,如果没有新消息,就会等待(阻塞),等到有新消息了,服务器才会返回响应(response)。
上面两种方式我们都会看到明显的缺点很消耗服务器的资源。然后我们就可能遇到 503 server Unavailable。
WebSocket的实例
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。(注意 ,这个http请求只是告诉我们的服务器接下来的请求是WebSocket请求,走的是WebSocket协议。通过这个建立起来这个连接通道。)
WebSocket api 使用
-
建立连接
const socket = new WebSocket('ws://localhost:8080');
-
连接成功后触发的api
// Connection opened socket.addEventListener('open', function (event) { socket.send('Hello Server!'); }); //两种写法是一样的 socket.onopen = function(){ socket.send('Hello Server!'); }
-
接受服务器发送的数据
socket.addEventListener('message', function (event) { console.log('Message from server ', event.data); }); // 还可以使用下面写法 socket.onmessage = function(event){ console.log('Message from server ', event.data); }
-
向服务器发送数据
socket.send('data')
-
关闭连接时触发的api
socket.addEventListener('close', function (event) { console.log('连接已关闭'); }); // 两种写法 socket.onclose = function() { // 关闭 websocket alert("连接已关闭..."); };
我只这里简单介绍几个常用的api,还有一些可以参考 MDN
在服务端(node)使用WebSocket
由于我们的原生的node并没有内置的这个接受WebSocket请求的方法,我们自己实现会比较麻烦,而且可能不稳定一般我们都会采用第三方的库。
-
不过了解原生的实现可以有助于我们的理解,大家可以参靠这篇文章 原生实现WebSocket应用
-
服务端第三方的库现在火的有两个一个是socket.io, 一个是ws,他们的用法还是比较类似的。
-
socket.io(分为客户端和服务端两个版本) 用法是比较简洁的,我这里简单介绍一下服务端用法。
socket.io 服务端 api
下面是一个简单的demo
var express = require('express')
var app = express()
const server = require('http').createServer(app)
const io = require('socket.io').listen(server)
users = []
server.listen( process.env.PORT ||4000)
console.log('server is running http://127.0.0.1:4000')
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html')
})
io.on('connection',function(socket) {
users.push(socket)
console.log('User connected: %s online',users.length)
socket.on('disconnect', function(data) {
users.splice(users.indexOf(socket),1)
})
socket.on('send msg',function(data) {
io.emit('chat msg',{msg: data})
})
})
- 通过这个小demo我们可以看出来我们的socket.io的用法首先要把包引入 并挂载到server上。
- 我们通过 socket 的实例 io,使用
io.on('connection',() ={})
与客户端建立连接。 - 我们可以使用
socket.on('disconnect',(data)=>{})
监听断开连接时。 socket.on('自定义内容',data => {})
监听我们客户端发送过来的内容。io.emit('key',data)
向所有的客户端广播数据。
这里简单介绍了几个api详细的还是需要去看官方文档。
我们可以发现我们这些api里面好像并没有指定发给某个客户端的api,那我们怎么实现类似聊天中的私聊的效果呢? — 我们这里其实可以采取客户端发送数据的时候不要只发送聊天内容,还要把自己的id 和发送对象的id发送过来类似于 io.send('data':{fromId:'1212',toId:'454645',chatMsg:'helloWorld'})
,这样我们就可以i解决这个私聊的问题。
总结
当然我们的WebSocket也不是没有缺点,我们的WebSocket建立起来一个长连接,这是非常吃我们的网络环境的,如果网不好,断网了,我们需要重连,就会出现很多问题,当然同时也要求我们的后端业务逻辑代码更加稳定。