websocket
粘包问题的处理
为什么会粘包?
- 发送数据的几种可能出现的情况
![image]()
假设客户端给服务器发送两个数据包:D1、D2,由于服务器一次从接收缓冲区中读取的字节数是不确定的,所以可能存在以下几种情况:
(1)服务器分别收到D1和D2,没有粘包和拆包;
(2)服务器一次收到D1和D2,称为TCP粘包;
(3)服务器分别读取了这两个数据包,第一次读到了D1的完整部分 和 D2的部分数据,第二次读到了D2的剩余部分,称为TCP拆包;
或者服务器第一次读取出D1的部分,第二次读出D1的剩余部分和D2的完整部分;
或者D1和D2都非常大,期间发生多次拆包。
-
发生粘包和拆包的原因:
(1)发送端:应用程序调用write()写入的字节大小大于套接口缓冲区的大小(拆包);
(2)发送端:进行MSS大小的TCP分片(拆包);
(3)发送端:基于Nagle算法的小包合并(粘包);
(4)接收端:应用程序调用read()读取的字节长度过小,可能发生拆包;read()读取过大,可能发生粘包。 -
解决方案:
由于底层协议无法理解上层的业务数据,所以依靠TCP层是无法保证数据不被拆分和重组的,只能通过应用层协议栈的处理来解决。- 固定大小
- 固定结尾字符(FTP)
- 将数据包分为包头包体(http, websocket, 等)
- 其他 高级且复杂的应用层协议
图解网络 3.9 既然有 HTTP 协议,为什么还要有 WebSocket?
需要注意的是,以下所讲的HTTP 在没有特殊强调的情况下都指HTTP 1.1 版本
简单的回答
我们的HTTP 协议的设计初衷是应对看看网页这类简单的场景,所以早期的HTTP 协议是只能由客户端发请求,服务端做出响应(半双工)。
实际应用中有很多需求是在客户端不进行任何操作的情况下,可以对页面进行更新。例如: 网页游戏,网页聊天室,广告、等、
对这种需求依赖不是很重的情况下 我们还可以借助轮训的方式去,假装服务器给我们推消息。但是需求很重的时候,HTTP 就没有办法胜任了。
所以有了websocket
场景演示 (在没有websocket的时候,我们如何实现使用http达到服务器类似的推送效果的)
短轮询(2s 一个接口)
图例:

- 访问csdn 登录
- fn + f12 (检查, 查看check login 轮训接口)
![image]()
存在问题是什么?
- 频繁请求消耗带宽
- 极端情况下,用户扫码后最长需要2s (设置的定时时长)才能得到响应,然后再等扫码后的请求响应回来,前端页面才能得到反馈。
更优解 长轮训(30 - 20s)

- 百度网盘扫码登录
-
fn + f12
扫码前

扫码后(请求参数变化了)

手机点击确认登录后,网页刷新页面,立马给页面返回数据渲染新的页面
为什么扫码点击确认后,服务端可以较为及时的响应客户端?![image]
长轮训有什么弊端?
我们为什么不直接http 2.0 推一个消息给客户端?
我们为什么不裸tcp 直接推送消息给客户端?
WebSocket 是什么
半双工: 同一时间里,只能单独一方给对方发送消息 ==> HTTP 1.1

全双工: 同一时间里,客户端、服务端均可以向对方发送消息 ==> TCP


基于TCP的应用层协议

WebSocket 与socket 有什么联系?

WebSocket 怎么建立连接
首先会进行一次HTTP 请求(请求协议切换);这里的请求会在请求头里面带特殊的参数

响应头里面也会有响应的信息(101)


手撕websocket
// 0 安装node.js 环境
// 1. 使用vs创建项目
// 2. 初始化package.json
npm init -y
// 3. 安装socket 依赖
npm i ws
// 4. 创建server.js
touch server.js
// 5. 使用node 启动服务器
node server.js
总结:
-
TCP 协议本身是全双工的,但我们最常用的 HTTP/1.1,虽然是基于 TCP 的协议,但它是半双工的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的 WebSocket 协议。
-
在 HTTP/1.1 里,只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
-
对于客户端和服务端之间需要频繁交互的复杂场景,比如网页游戏,都可以考虑使用 WebSocket 协议。
-
WebSocket 和 socket 几乎没有任何关系,只是叫法相似。
-
正因为各个浏览器都支持 HTTP协 议,所以 WebSocket 会先利用HTTP协议加上一些特殊的 header 头进行握手升级操作,升级成功后就跟 HTTP 没有任何关系了,之后就用 WebSocket 的数据格式进行收发数据。
本文来自博客园,作者:shafujiu,转载请注明原文链接:https://www.cnblogs.com/shafujiu/articles/17369917.html



浙公网安备 33010602011771号