文章目录
ws建立过程
1、客户端发送 http 请求,经过三次握手,建立 TCP连接,在 http 请求里存放 websocket 支持的版本号等信息;
2、服务器接收请求,同样以 http 协议回应;
3、连接成功,客户端与服务器建立持久性的连接。
http和tcp相同点
- 都是 TCP 协议;
- 都使用 Request/Response 模型进行连接的建立;
- websocket 是基于 http 的,他们的兼容性都很好;
- 在连接的建立过程中对错误的处理方式相同;
- 都可以在网络中传输数据。
http和tcp不同点
- websocket 是持久连接,http 是短连接;
- websocket 的协议是以 ws/wss 开头,http 对应的是 http/https;
- websocket 是有状态的,http 是无状态的;
- websocket 连接之后服务器和客户端可以双向发送数据,http 只能是客户端发起一次请求之后,服务器才能返回数据;
- websocket 是可以跨域的;
- websocket 连接建立之后,数据的传输使用帧来传递,不再需要Request消息。
websocket协议涉及到HTTP头部
- 请求头:
- WebSocket 请求一定是 GET 类型的。
Origin
: 浏览器客户端会带上,包含 Origin 是为了安全考虑,充分利用浏览器的同源策略。Connection
: Upgrade 和 Upgrade: websocket。这是客户端告知服务端需要升级协议,并且升级的协议为 websocket。Sec-WebSocket-Key
:由客户端(比如浏览器)随机生成,16位随机数经过 base64 编码后得到。响应头 Sec-WebSocket-Accept 是与它搭配使用的,用来确保请求的有效性和安全性。Sec-WebSocket-Protocol
:不是必选的。用来约定应用层面的子协议,使得客户端和服务器能够灵活地协商并选择一个双方都能理解的协议来进行通信。如果服务端选择使用某个子协议通信,则会在响应头中返回
- 响应头:
- 服务端返回 101 Switching Protocols,代表握手成功,协议切换到 WebSocket。
如果客户端尝试通过普通的 HTTP 请求来连接 WebSocket 服务,服务端应该返回 426 Upgrade Required 告诉客户端,“你该升级协议再跟我对话!”
Connection
: Upgrade 和 Upgrade: websocket,用于告知客户端可以升级为 websocket 协议。Sec-WebSocket-Accept
:基于 Sec-WebSocket-Key 处理得到,处理公式如下,其中"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"是一个固定的字符串
websocket数据帧:
FIN
,占1bit,如果是1,表示这是消息(message)的最后一个分片(fragment),如果是0,表示不是是消息(message)的最后一个分片(fragment)。RSV1
, RSV2, RSV3,各占1bit,一般情况下全为0。当客户端、服务端协商采用WebSocket扩展时,这三个标志位可以非0,且值的含义由扩展进行定义。如果出现非零的值,且并没有采用WebSocket扩展,连接出错。Opcode
,占4bit,操作代码,Opcode的值决定了应该如何解析后续的数据载荷(data payload)。如果操作代码是不认识的,那么接收端应该断开连接(fail the connection)。Mask
,占1bit,表示是否要对数据载荷进行掩码操作。从客户端向服务端发送数据时,需要对数据进行掩码操作;从服务端向客户端发送数据时,不需要对数据进行掩码操作。
如何保证数据正确且送到了
- 消息确认和重传
- 消息序列号
- ReconnectingWebSocket
- 每条记录都有id 每次请求客户端保留一个最大id 以后每次重连 都需要查询比这个id新的记录就行了
websocket连接断开期间的消息会丢失吗,怎么重连?
let websocket = null;
let reconnectTimer = null;
function connectWebSocket() {
websocket = new WebSocket('ws://localhost:8000');
websocket.addEventListener('open', function() {
console.log('WebSocket connected!');
clearInterval(reconnectTimer);
});
websocket.addEventListener('message', function(event) {
console.log('Received message:', event.data);
});
websocket.addEventListener('close', function(event) {
console.log('WebSocket closed with code', event.code, 'and reason', event.reason);
reconnectWebSocket();
});
websocket.addEventListener('error', function(error) {
console.error('WebSocket error:', error);
reconnectWebSocket();
});
}
function reconnectWebSocket() {
if (websocket && websocket.readyState === WebSocket.OPEN) {
return;
}
clearTimeout(reconnectTimer);
reconnectTimer = setTimeout(function() {
console.log('Reconnecting WebSocket...');
connectWebSocket();
}, 3000); // 等待 3 秒后尝试重新连接
}
connectWebSocket(); // 初始连接
实现一个聊天室
基于Socket.IO,它支持心跳检测、优雅降级、房间隔离、命名空间隔离、API 的易用性等
当我们打开一个 Socket.IO 的客户端页面时,会发现 Network 里发出了多个请求,在 101 websocket 连接建立之前,有 4 个 xhr 请求,其中还有一个是 POST 请求。
功能:
1. 确保当前没有待发送的数据在缓冲区中
2. 将当前传送方式调至只读模式
3. 尝试与其他传输端建立连接
4. 如果成功,关闭第一个传输
实现过程:
- 服务端开启 WebSocket 服务
监听connection,表示有客户端请求。 - 客户端服务端建立连接
// 引入依赖,得到一个socket实例
import io from "socket.io-client";
createSocket() {
const self = this;
this.socket = io(process.env.VUE_APP_SOCKET_SERVER + "/chatroom");
this.socket.on('connect', ()=>{})
...
}
- 聊天室的系统通知信息
- 聊天对话功能
this.socket.emit('chat', ()=>{})