【NPM库】- 0x06 - WebSocket
目录
1. WebSocket
1.1. 是什么?
1.2. 一个例子
1.3. 连接建立过程
2. ws
2.1. 基础
2.2. 简易 Server
2.3. 复用 HTTP 连接
3. webpack-dev-server 对 WebSocket 的应用
3.1. 总体结构
3.2. WebSocket 后端
3.3. WebSocket 前端
1. WebSocket
1.1. 是什么?
WebSocket 是一种通信协议,可在单个 TCP 连接上进行全双工通信。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。
- 握手阶段采用 HTTP 协议
- 数据格式轻量,性能开销小(HTTP每次都需要携带完整头部)
- 服务端到客户端的数据包头只有2到10字节。
- 客户端到服务端需要加上另外4字节的掩码。
- 更好的二进制支持
- 可以发送文本、二进制数据
- 没有同源限制,客户端可以与任意服务器通信
- 协议标识符是ws(如果加密,则是wss)
1.2. 一个例子
效果展示:
后端代码:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send(`echo: ${message}!`);
});
ws.send('connected!');
});
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
.websocket {
width: 800px;
border: 1px solid #ccc;
margin: 16px auto 0 auto;
display: flex;
flex-direction: row;
}
.websocket p {
text-align: center;
}
.websocket > .send {
flex: 1;
padding: 16px;
border-right: 1px solid #ccc;
}
.websocket > .send > .msg-send{
width: 100%;
height: 200px;
border-radius: 5px;
}
.websocket > .send .btn-send {
border: none;
border-radius: 5px;
background: #25d1ff;
padding: 5px 10px;
color: #fff;
cursor: pointer;
}
.websocket > .send .btn-close {
border: 1px solid #ccc;
border-radius: 5px;
background: none;
padding: 5px 10px;
cursor: pointer;
}
.websocket > .receive {
flex: 1;
padding: 16px;
}
.websocket > .receive > .msg-receive {
height: 200px;
border: 1px solid #ccc;
border-radius: 5px;
overflow: auto;
}
.websocket > .receive > .msg-receive > .msg-item{
font-size: 14px;
}
</style>
</head>
<body>
<div class="websocket">
<div class="send">
<p>数据发送</p>
<textarea type="text" class="msg-send"></textarea>
<p>
<button class="btn-send">发送消息</button>
<button class="btn-close">关闭连接</button>
</p>
</div>
<div class="receive">
<p>数据接收</p>
<div class="msg-receive"></div>
</div>
</div>
<script type="text/javascript">
const ws = new WebSocket('ws://127.0.0.1:8080');
ws.onopen = e => {
console.log(`WebSocket 连接状态:${ws.readyState}`)
};
ws.onmessage = data => {
const msgReceive = document.querySelector('.websocket > .receive > .msg-receive');
msgReceive.innerHTML += `<div class="msg-item">${data.data}</div>`;
};
ws.onclose = data => {
console.log('WebSocket连接已关闭')
console.log(data);
};
// 发送消息
const btnSend = document.querySelector('.websocket > .send .btn-send');
const msgSend = document.querySelector('.websocket > .send > .msg-send');
btnSend.onclick = () => ws.send(msgSend.value);
// 关闭链接
const btnClose = document.querySelector('.websocket > .send .btn-close');
btnClose.onclick = () => ws.close();
</script>
</body>
</html>
1.3. 连接建立过程
- 客户端发起HTTP握手,告诉服务端进行WebSocket协议通讯,并告知WebSocket协议版本。
- 服务端确认协议版本,升级为WebSocket协议。
- 之后如果有数据需要推送,会主动推送给客户端。
请求字段重点包括:
- Connection: Upgrade,表示请求升级协议
- Upgrade: websocket,表示请求升级到 websocket 协议
- Sec-WebSocket-Version,表示 websocket 的版本。
- 如果服务端不支持该版本,需要返回一个Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。
- Sec-WebSocket-Key,对应服务端响应头的Sec-WebSocket-Accept,由于没有同源限制,websocket 客户端可任意连接支持websocket的服务。这个就相当于一个钥匙一把锁,避免多余的,无意义的连接。
响应字段重点包括:
- Sec-WebSocket-Accept:用来告知服务器愿意发起一个 websocket 连接, 值根据客户端请求头的 Sec-WebSocket-Key 计算出来。
2. ws
2.1. 基础
- ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and server implementation.
2.2. 简易 Server
const WebSocket = require('ws');
const ws = new WebSocket('ws://www.host.com/path');
ws.on('open', function open() {
const array = new Float32Array(5);
for (var i = 0; i < array.length; ++i) {
array[i] = i / 2;
}
ws.send(array);
});
2.3. 复用 HTTP 连接
- Multiple servers sharing a single HTTP/S server
const http = require('http');
const WebSocket = require('ws');
const url = require('url');
const server = http.createServer();
const wss1 = new WebSocket.Server({ noServer: true });
const wss2 = new WebSocket.Server({ noServer: true });
wss1.on('connection', function connection(ws) {
// ...
});
wss2.on('connection', function connection(ws) {
// ...
});
server.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === '/foo') {
wss1.handleUpgrade(request, socket, head, function done(ws) {
wss1.emit('connection', ws, request);
});
} else if (pathname === '/bar') {
wss2.handleUpgrade(request, socket, head, function done(ws) {
wss2.emit('connection', ws, request);
});
} else {
socket.destroy();
}
});
server.listen(8080);
3. webpack-dev-server 对 WebSocket 的应用
3.1. 总体结构
3.2. WebSocket 后端
- webpack-dev-server 的 WebSocket 通信默认采用 sockjs 实现。
- 可通过 transportMode 属性进行调整。
- webpack-dev-server 复用提供 Web 服务的 Server。
- sockjs-node 是默认的 websocket 服务访问路径。
- 可通过 devServer.sockPath 属性自行定制。
- sockjs-node 是默认的 websocket 服务访问路径。
webpack-dev-server 的 CLI 入口:
webpack-dev-server 如何选择 WebSocket 的 Server 端实现:
webpack-dev-server 如何确定 WebSocket 的服务地址:
3.3. WebSocket 前端
- webpack-dev-server 的 WebSocket 通信默认采用 sockjs 实现。
- 可通过 transportMode 属性进行调整。
- webpack-dev-server 的 WebSocket 前端,是作为一个入口,自动注入到应用系统中的。
webpack-dev-server 的 WebSocket 前端实现何时选定?:
webpack-dev-server 的 WebSocket 前端实现何时选定?:
webpack-dev-server 的 WebSocket 前端如何加载?:
参考:
ws: https://github.com/websockets/ws webpack-dev-server: https://www.webpackjs.com/configuration/dev-server/ webpack-dev-server 配置: https://webpack.js.org/configuration/dev-server/#devserversockpath https://webpack.js.org/configuration/dev-server/#devservertransportmode
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 小程序的模板化编程
- mongodb创建集合与php扩展
- 编写第二个页面:新闻阅读列表页面
- jQuery用于请求服务器的函数
- jQuery的简单使用
- 编写第一个小程序页面
- 在CentOS7下安装MongoDB
- redis集群搭建
- redis慢查询日志,php安装redis扩展,redis存储session,redis主从配置
- jQuery介绍与常见选择器的使用
- redis常用操作,redis操作键值,redis安全设置
- redis介绍,redis安装,redis持久化,redis数据类型
- AJAX的post请求与上传文件
- memcached的一些简单使用
- nosql介绍,memrcached介绍,安装memcached,查看memcachedq状态