本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
WebSocket基础概念
WebSocket 是一种在浏览器和服务器之间建立持久连接来交换数据的方法。直观来说, 它基于tcp,先通过HTTP/HTTPS协议发起一条特殊的http请求进行握手后创建一个用于交换数据的TCP连接协议。 是不同于http的一种协议。
连接过程
当 new WebSocket(url) 被创建后,它将立即开始连接。
在连接期间,浏览器(使用 header)问服务器:“你支持 WebSocket 吗?”如果服务器回复说“我支持”,那么通信就以 WebSocket 协议继续进行,注意该协议不是 HTTP。
用三个端口来演示WebSocket的运行过程
WebSocket的主要特点是长连接和双向通信,其中双向通行是实现即时通信,通知等功能的关键。
这里我们使用Koa和socket.io来快速实现两个端口模拟的即时通讯效果,从而直观的感受下WebSocket的作用。
(注:这里的socket.io是一个实现WebSocket的包,以下的实例,是经过官网的实例改进而成的,有兴趣的可以去官网了解一下 Socket.IO )
搭建两个端口:
const Koa = require("koa");
const { createServer } = require("http");
const { Server } = require("socket.io");
const app = new Koa();
const httpServer = createServer(app.callback());
//注意多个端口要解决一下跨域问题
const io = new Server(httpServer, { cors:{
origin:'http://localhost:3001'
} });
io.on('connection', (socket) => { //监听WebSocket的连接
console.log('一个用户开始连接',socket.id)
socket.on('chat message', (msg) => { //监听chat message
io.emit('chat message from 3000', msg); //发送chat message from 3000及其包含的数据
});
socket.on('disconnect', () => {
console.log('一个用户断开连接');
});
});
httpServer.listen(3000,()=>{
console.log('start 3000')
});
//index2.js 3001端口,用来模拟用户发送和接收信息
const Koa = require("koa");
const { createServer } = require("http");
const router = require('koa-router')();
const static = require('koa-static')
const app = new Koa();
const httpServer = createServer(app.callback());
app.use(router.routes());
router.get('/',static(__dirname+'/public')) //静态网页显示
httpServer.listen(3001,()=>{
console.log('start 3001')
});
服务器引用的静态页面
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 5rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; font-size: 50px;}
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
<!--CDN加载socket.io-->
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/4.1.3/socket.io.js"></script>
<script>
var socket = io('http://localhost:3000'); //向3000端口发起连接请求
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value); //发送 chat message
input.value = '';
}
});
socket.on('chat message from 3000', function(msg) { //监听'chat message from 3000',并将其数据动态渲染到页面
var item = document.createElement('li');
item.textContent = msg;
item.style.fontSize = '50px'
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
</body>
</html>
之后我们启动两个端口,然后分别在浏览器上打开两个3001端口,在3001端口,我们可以看到:
在服务器端,我们可以看到3000端口打印出了如下内容:
可以看到,两个3001端口,分别建立两个WebSocket连接,同时生成了两个socket.id来区分不同的用户。
我们在第一个页面发送消息,可以看到,这则消息通过服务器的广播,分别发送给了两个已经建立连接的页面发送了消息:
通过样例,我们可以很容易的看到,WebSocket实现了双端通信的效果。
WebSocket知识点(补)
WebSocket常用状态码
1000 CLOSE_NORMAL 正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
1001 CLOSE_GOING_AWAY 终端离开, 因为服务端错误或浏览器跳转到其他页面或关闭
1009 CLOSE_TOO_LARGE 由于收到过大的数据帧而断开连接.
1011 Internal Error 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.
连接状态
0—— “CONNECTING”:连接还未建立,1—— “OPEN”:通信中,2—— “CLOSING”:连接关闭中,3—— “CLOSED”:连接已关闭。
其他
- 浏览器对WebSocket支持很好
- WebSocket可以发送/接收字符串和二进制数据
- 注意websocket需要长连接的支持。