大厂技术  坚持周更  精选好文

一、首先我们要了解 Websocket 握手的原理

请求头特征

  • HTTP 必须是 1.1 GET 请求

  • HTTP Header 中 Connection 字段的值必须为 Upgrade

  • HTTP Header 中 Upgrade 字段必须为 websocket

  • Sec-WebSocket-Key 字段的值是采用 base64 编码的随机 16 字节字符串

  • Sec-WebSocket-Protocol 字段的值记录使用的子协议,比如 binary base64

  • Origin 表示请求来源

响应头特征

  • 状态码是 101 表示 Switching Protocols

  • Upgrade / Connection / Sec-WebSocket-Protocol 和请求头一致

  • Sec-WebSocket-Accept 是通过请求头的 Sec-WebSocket-Key 生成

二、短连接轮询、长连接、Websocket 横向对比

1. 短连接轮询

  • 很耗费 TCP 连接

  • 而且 Header 重复发送

  • 且通过宏任务发起,受限于 Event Loop,无法保证及时性

  • 同时无效请求会很多

2. 长连接

  • HTTP keep-alive 开启后虽然 TCP 可以复用,但是 Header 重复的问题并没有解决

  • 同时 HTTP keep-alive 还有一个有效期,有效期结束后服务端会发侦查帧探查 TCP 是否有效

题外话:

HTTP keep-alive 的作用是,告知服务端持久化当前的 TCP 连接,不要立即断开,以便后续的 HTTP 请求复用它,也就是我们所说的「长连接」

HTTP 的 keep-alive 是为了让 TCP 活久一点,而 TCP 本身也有一个 keepalive(注意没有横杠哦)机制。这是 TCP 的一种检测连接状况的保活机制,keepalive 是 TCP 保活定时器:TCP 建立后,如果闲置没用,服务器不可能白等下去,闲置一段时间[可设置]后,服务器就会尝试向客户端发送侦测包,来判断 TCP 连接状况,如果没有收到对方的回答(ACK包),就会过一会[可设置]再侦测一次,如果多次[可设置]都没回答,就会丢弃这个 TCP 连接

(TCP keepalive 保活示意图)

3. Websocket

  • 和 HTTP 一样都是建立在 TCP 协议之上,但只需一次 HTTP 握手,就能建立持久性连接,后续就不走 HTTP 了,而是 WebSocket 特有的数据帧

  • 全双工通信,双向数据传输

  • 数据格式轻量,且支持发送二进制数据,支持 ws 和加密的 wss

三、我在微信小程序中利用 WebSocket 都捣鼓了什么?

1 验签鉴权及对应的容错策略(登录态要求、峰值访问、服务端宕机异常)

背景与目的:

  • websocket 握手后,接口请求即可以放弃 HTTP 改走 weboskcet,但大部分业务接口都要求登录态,因此握手成功后必须先走一次签名鉴权,获取登录态

  • 当出现大流量访问的场景(如大促、热点活动等)或服务端出 bug 而导致服务端宕机,前端会做 对应容错,将位于内存的等待队列中的待发送请求立即降级成 HTTP 发送出去

伪码示意:

SocketTask.onOpen(function () {SocketTask.sendSocketMessage({msg_type: '验签',token: 'xxx'}, (response) => {console.log(response.user_id, response.access_token)// 通道可用,打个标记global.isSocketAvaliable = true;})
})

2 心跳保活(减少 TCP 占用)

背景与目的:为了减少 TCP 连接的无效占用,客户端定时发送一个空包到服务端,告知服务端不要销毁这条 socket,如果服务端超过一定时间都没收到心跳包,则将关闭并销毁该 socket

伪码示意:

SocketTask.onOpen(function () {SocketTask.sendSocketMessage({msg_type: '验签',token: 'xxx'}, (response) => {console.log(response.user_id, response.access_token)// 通道可用,打个标记global.isSocketAvaliable = true;// 验签成功,开始定时发送心跳包setInterval(() => {SocketTask.sendSocketMessage({msg_type: '心跳'});});});
})

3 模拟 RTT(用于弱网体验优化)

背景与目的:在发送心跳包时,可得知一个心跳包的 RTT,以此模拟当前用户网络环境的 TCP RTT,并据此计算出平滑 RTO,用于弱网体验优化

伪码示意:

SocketTask.onOpen(function () {SocketTask.sendSocketMessage({msg_type: '验签',token: 'xxx'}, (response) => {console.log(response.user_id, response.access_token)// 通道可用,打个标记global.isSocketAvaliable = true;// 验签成功,开始定时发送心跳包setInterval(() => {// 计算 RTTconst begin = Date.now();SocketTask.sendSocketMessage({msg_type: '心跳'}, () => {const end = Date.now();const RTT = begin - end;const smoothedRTO = cal(RTT);global.smoothedRTO = smoothedRTO;});});});
});

4 Snappy 压缩(横向对比了 gzip / zip / 7z)

背景与目的:在小程序中引入第三方压缩包(牺牲小程序包体积),减少 websocket 传输的字节数

伪码示意:

import Snappy from 'snappy';SocketTask.sendSocketMessage = function (msg) {const encryptedMsg = Snappy.encode(msg);wx.send(encryptedMsg);}

5 重连(阶梯式错位重连,避免拥挤)

背景与目的:用户的网络环境不稳定,可能会存在主动 / 被动断开 socket 的情况,需要进行自动重连

伪码示意:

SocketTask.onClose(function () {// 限定最大重连次数if (retryCount > maxCount) {return;}retryCount++;setTimeout(() => {SocketTask.connectSocket();}, retryCount * 1000 + Math.random() * 1000);
});

6 埋点中间层缓存(重复的用户信息可以不用每次都上报,支持刷新缓存)

背景与目的:为减少网络传输的包体积,通过 websocket 上报埋点日志时,可以把部分重复字段值在第一次上报时缓存在服务端,从第二次上报开始只上报值不重复的字段,然后由服务端做日志合并

伪码示意:

SocketTask.sendSocketMessage({msg_type: '埋点日志',logs: {country: 'China', // 可缓存字段city: '北京', // 可缓存字段platform: '安卓', // 可缓存字段click_some_btn: true // 动态变化的埋点字段},cacheFields: ['country', 'city', 'platform'] // 只在第一次上报时携带});

7 启用 TCP_NODELAY

TCP_NODELAY 是用来禁用 Nagle 算法的。Nagle 算法设计的目的是提高网络带宽利用率,其核心思路是「合并小的 TCP 包为一个大的 TCP 包」,避免过多的小包的 TCP 头部浪费网络带宽

参考资料:https://www.zhihu.com/question/42308970

H5-Dooring, 让H5制作, 更简单

❤️ 谢谢支持

以上便是本次分享的全部内容,希望对你有所帮助^_^

喜欢的话别忘了 分享、点赞、收藏 三连哦~。

Websocket 可以玩出些什么花儿?相关推荐

  1. Websocket 可以玩出些什么花儿?(建议收藏)

    一.首先我们要了解 Websocket 握手的原理 请求头特征 HTTP 必须是 1.1 GET 请求 HTTP Header 中 Connection 字段的值必须为 Upgrade HTTP He ...

  2. websocket协议以及在gin中的应用

    目录 websocket协议简介 WebSocket 协议的来源 短轮询 本质 实现 应用场景 优缺点 长轮询 本质 实现 应用场景 优缺点 WebSocket协议 websocket定义及与HTPP ...

  3. 【知识分享】C语言应用——指针篇

    一.概述     C语言基础大部分都很好理解,唯一入手门槛比较高的,就数指针了.指针是C语言的一大特色,因为指针,C语言可以极度灵活,但也因为指针,C语言变得很不安全.指针就是一把双刃剑,用好了可以让 ...

  4. RunTime 入门

    原文链接:http://www.jianshu.com/p/59992507f875 这是一篇浅显实用 易记 易理解的关于runtime的解读. Runtime 中的方法主要以五个单词开头--clas ...

  5. (译)Objective-C的动态特性

    这是一篇译文,原文在此,上一篇文章就是受这篇文章启发,这次干脆都翻译过来. 过去的几年中涌现了大量的Objective-C开发者.有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型 ...

  6. 过于离谱,我实现憋不住了!

    大家好,我是张巧龙,在知乎,看到了一个问题: 这就是一个求阶乘的问题,大家刚刚开始学编程的时候应该都写过这样的程序. 一个求阶乘的问题,还能玩出什么样的花儿来? 我在回答区看到了一个非常有趣的回答,把 ...

  7. iOS运行时-使用Runtime向Category中添加属性以及运行时介绍

    前言 了解OC的都应该知道,在一般情况下,我们是不能向Category中添加属性的,只能添加方法,但有些情况向,我们确实需要向Category中添加属性,而且很多系统的API也有一些在Category ...

  8. Objective-C 的动态提示和技巧

    2019独角兽企业重金招聘Python工程师标准>>> 过去的几年中涌现了大量的Objective-C开发者.有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型语言 ...

  9. 双十一品牌——官方首度揭秘设计全过程!

    一年一度的双十一全球狂欢节来了! 相信大家之前也通过各种途径看到了双十一的品牌渗透,之前也有过不少猜想,今年双十一品牌到底在玩什么,背后的思考是什么?今天阿里官方设计师首度向大家揭秘双十一品牌设计的心 ...

最新文章

  1. Ubuntu 12.04 64bit或者CentOS 6.3 64bit上搭建OpenRTMFP/Cumulus服务器
  2. Python基础编程——字典的创建
  3. ios微信登录不上服务器,iOS微信授权登录
  4. 2.3.3 spring属性注入-注解注入-全注解-配置类扫描
  5. 数据库:mongodb与关系型数据库相比的优缺点zz
  6. 关于眼保健操中的轮刮眼眶
  7. 统计多维数组php_PHP多维数组中统计元素个数
  8. ORA-23616:执行块5失败
  9. 计算机应用技术与英语相关性,浅析计算机应用的技术专业的计算机专业英语的教学改进.doc...
  10. WF4.0 RC 对比 Beta2 的变化
  11. 81_如何用eclipse反编译一个war包或者jar包
  12. 小程序 | 微信小程序布局左对齐自动换行
  13. 在Colaboratory中使用ImageAI训练自己的数据集
  14. 液晶屏COG封装技术-工业显示领域主流
  15. c语言尹宝林答案,离散数学 尹宝林版 第7章作业答案
  16. Week10 限时大模拟 B - 东东转魔方 HDU - 5983
  17. 大数据在职研究生哪个好_报考大数据在职研究生未来的就业的方向有哪些
  18. 计算机体系结构 公开课,清华大学公开课:操作系统
  19. 深入理解面向discuz的插件开发
  20. 从小白到大牛需要的iOS 基础这里都有,需要的过来看看!

热门文章

  1. python在pip安装pytorch时候killed
  2. bq24773功能分析(中文手册翻译)
  3. 最小差值(java)
  4. 某校2019专硕编程题-排序
  5. 鼠标跨屏操作(无需添加外设)-- Mouse without Borders
  6. 基于Mxnet的车辆重识别(Re-ID)之数据集处理(以VeRi为例)
  7. 安卓新手如何学习开发一款游戏APP呢?
  8. php读取和创建word文档
  9. 【HTML】三种加载动画
  10. 私有云:何去何从?解决方案有哪些