[转帖]websocket的一点笔记

websocket,一点,笔记 · 浏览次数 : 0

小编点评

**WebSocket 协议** WebSocket 是一种基于 TCP 的双向通信协议,它允许客户端和服务器建立并维护长连接,并实时双方向地通信。 **WebSocket 与 HTTP 的关系** WebSocket 可以与 HTTP 协议一起使用,但它们不是同一件事。**HTTP**是一种基于 HTTP 协议的请求和响应协议,它用于传输网页内容。**WebSocket**是一种基于 TCP 协议的协议,它用于传输无状态数据,例如音频、视频和聊天消息。 **WebSocket 的帧结构** WebSocket 数据帧是一个 JSON 对象,它包含以下信息: * **数据**:发送方或接收方发送的数据。 * **类型**:帧的类型,例如 "text", "image" 或 "binary"。 * **长度**:数据或帧的长度。 * **结束标志**:用于终止帧的标志,例如 "close" 或 "end"。 **结束符** WebSocket 协议支持使用结束符来关闭连接。当客户端关闭 WebSocket 连接时,它发送一个 "close" 或 "end" 帧,并关闭连接。 **锁机制** 为了防止多个客户端使用相同的 WebSocket 连接,WebSocket 协议使用锁机制。客户端必须首先获得锁,才能发送或接收数据。锁机制确保了连接的可靠性和安全性。 **子协议** WebSocket 协议支持一些子协议,这些子协议用于扩展协议的功能。例如,WebSocket-RTMP 协议用于传输实时音频和视频。

正文

https://zhuanlan.zhihu.com/p/35568719

 

因为工作中没有用过websocket,所以对这个协议也不是很了解。但是网上经常看到这个协议,感觉不去了解一下,也不合适。

以前自己基础功不扎实的时候,我一直不知道所谓的网络协议到底是个什么意思?到底和TCP有什么区别?因为基础不扎实,所以对遇到的问题甚至都无法描述出来,那种感觉就像在迷雾中一般。

后来因为特别想知道公司用的fan qiang工具是怎么实现的,于是去阅读了同事的开源项目,第一次明白了所谓的网络协议是怎么一回事。后面再去阅读了两本TCP/IP方面的书,以及HTTP权威指南,再阅读了mongo的驱动实现以及Go的http库的实现,对网络协议这个东西,总算是知道个怎么一回事了。

总得来说,目前看过的协议主要是这几类:基于二进制数据和基于文本,或者基于流的和基于帧的。

所谓的基于二进制,就是你给我10101010这样的数据,我这个协议呢,就把你的数据封装一下,比如在你的数据的前面再加上100010000封装为10001000010101010,我前面的这一串二进制数据,可以设定各种含义,比如我假设第一位如果是0,表示这是文字信息,如果是1表示这是图像数据。然后就把10001000010101010发给支持这种协议的服务器。服务器读到一份数据,它就根据头部的这一堆1和0解析出这份数据的含义。

而基于文本的协议,典型的如http,它的协议格式大致如下:

POST /hello HTTP/1.1
Host: 127.0.0.1:8989
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,la;q=0.2
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 36
Content-Type: application/x-www-form-urlencoded
Origin: chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo
Postman-Token: b98e76e9-3552-b53d-c9a6-ae7d425e99ef
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36

first=I+am+first&second+=I+am+second

这份数据在传输的时候也是1和0,只不过我解析它含义的时候,不是在它们还是0和1来判断的,而是根据字符串,比如我要知道你发送的数据类型,就要去找Content-type这个部分(基于二进制的协议,我只要根据你头部二进制的第N位或者第N几位的值就能判断你的数据类型)。

基于帧和基于流的划分,则简单一点。TCP协议本身就是基于流的,但是基于TCP上的大部分应用协议都是基于帧的。基于流的协议,就是不管接收到的数据边界,收到一份就是一份。比如‘国’这个字转换成0和1之后,通过TCP传输,可能是被分成了前后两份,因为TCP不负责数据的解释,它只认0和1,tcp把数据收完之后,把所有收到的二进制数据按顺序整合在一起,交给上层协议去解析。

websocket就是基于TCP的上层应用协议,它是按照帧的。websocket从tcp拿到一组0和1 的数据,它先读取一小部分,这是帧头部,长度是固定的,然后开始根据协议定义的每一位代表什么意思,解析出这份数据的基本信息,比如数据长度是多长。然后根据数据的长度,把完整的一帧读取下来。读到终结帧的时候,就把所有帧中的数据组合起来交给上一层。

所以,定义一个网络协议,首先确定是基于二进制还是基于文本,是基于流的还是基于帧的。然后要定义元数据,就是你给我一份数据,我该如何知道这个0是什么意思,那个1是什么意思,我该怎么做。接着就要定义数据该怎么发送怎么接收了。

读了一遍websocket的RFC,再读了下Go的一个websocket协议实现,把我目前疑惑的地方都解决了。关于websocket的详细信息,网上其实已经非常多了,对我来说,因为之前那些疑惑的存在,我一直都没有看明白网上的那些websocket教程和文章。现在疑惑解除了,看网上的那些教程基本没压力。所以本文不是正规的websocket教程或者科普文。

首先我的第一个疑惑就是websocket和http有什么关系?其实websocket可以和http没有关系的。只是因为web前端面临的环境比较复杂,比如到现在还有人在用着IE6,这显然是不可能再增加新功能新支持的了。另外各家浏览器大厂都有自己的利益诉求,不可能随便支持你给出的一个东西。所以websocket利用http协议来进行与服务器握手,可以保证得到最广泛的客户端支持。而在服务器上,每个人都可以根据自己的需求去决定是否支持websocket,这个要做起来就容易多了。

所以websocket就利用了http,比如我客户端要建立一个websocket连接,就先发一个http请求,这个http请求的头部存在如下字段:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

假如你的服务器是支持websocket的,那么它就回复一个接受握手:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

此时客户端和服务器之间就建立了一条tcp连接,服务器知道这条连接是专门用于websocket的,你有需求就往里面发送websocket帧。

现在已经没有http协议什么事了。其实上面这个过程,也是可以不经过http的。你给我服务器的地址和端口,我直接建立一个tcp连接,然后发送一小段消息,由对方去解析明白这是用于websocket的。

里面http来进行握手,可以确保http服务的端口也能被websocket使用,减少端口的暴露和配置。同时保证了多数客户端都能支持websocket的握手。握手成功之后,就是tcp的事情了,大多数客户端都能支持了(解析留给库去解决就行)。

比较有趣的是在握手的过程中,客户端会发送一个Sec-WebSocket-Key的头部,它是一个SHA-1构造出来的信息摘要,并进行过base64编码。然后服务器端验证完之后,返回给客户端时添加一个Sec-WebSocket-Accept的头部,其值是客户端发来的Sec-WebSocket-Key的值,加上一个固定的字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然后进行base64编码。客户端解析这个值就能判断出是否接受了。

WebSocket是分帧的,小一点的数据就一帧就结束了。而对于大的数据,比如一张图片,那么就需要分很多帧。websocket帧的结构可以看这篇文章:Websocket协议数据帧传输和关闭连接 。因为分帧,所以就要有结束标志,websocket里有一个结束帧,收到这个帧表示这份数据接收完毕。读完RFC和代码后,确实如RFC所说,websocket不支持多路复用,往同一个方向上的数据发送,同时只能有一个client,只有等这个client发送完毕 ,才能给其他client使用这条tcp连接。所以RFC里面要求client在使用websocket的时候需要加锁。这种设置也导致了它不那么高效(http2就可以做到多路复用),但是协议的实现也相对简单了许多。

websocket建立握手的过程中会有一个Origin头部,这个是client所在的域名,主要是用于浏览器时防止跨域攻击,譬如你是http://example.com的,就不能在浏览器中给发消息(其实可以发,只是对端服务器会拒绝掉)。这个头部是浏览器设置的,所有的js库都不能修改这个头部的值,保证了websocket的安全。

websocket还有个子协议,搞得我比较头晕的。仔细了解了下,其实就类似于你在TCP上实现了websocket,这些子协议只是在websocket上实现的。简单点说就是websocket一端收到websocket数据,然后提取出里面数据部分(去掉帧的元信息),然后再用另一种协议定义来解析这部分数据。

与[转帖]websocket的一点笔记相似的内容:

[转帖]websocket的一点笔记

https://zhuanlan.zhihu.com/p/35568719 因为工作中没有用过websocket,所以对这个协议也不是很了解。但是网上经常看到这个协议,感觉不去了解一下,也不合适。 以前自己基础功不扎实的时候,我一直不知道所谓的网络协议到底是个什么意思?到底和TCP有什么区别?因为基

[转帖]Nginx支持WebSocket反向代理

https://www.cnblogs.com/zhengchunyuan/p/12923692.html WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择。其为HTML5的一部分,WebSocket相较于原来开发这类

[转帖]Nginx的热加载

https://www.zhihu.com/question/531861487/answer/2850763798 有websocket 时并不能立即生效.. 这段时间在 Reddit 看到一个讨论,为什么 NGINX 不支持热加载?乍看之下很反常识,作为世界第一大 Web 服务器,不支持热加载?

[转帖]websocket消息推送设计

https://cloud.tencent.com/developer/article/2168088?areaSource=&traceId= 1. 背景 公司内目前有几个项目都有消息推送的功能,例如:某个业务操作之后需要推送消息给前端页面,让用户实时感知。 但是目前公司内的消息推送实现分散在在各

[转帖]Real-Time Web Applications with WebSocket and NGINX

https://www.nginx.com/blog/realtime-applications-nginx/ In the blog post NGINX as a WebSocket Proxy we discussed using NGINX to proxy WebSocket applic

[转帖]

Linux ubuntu20.04 网络配置(图文教程) 因为我是刚装好的最小系统,所以很多东西都没有,在开始配置之前需要做下准备 环境准备 系统:ubuntu20.04网卡:双网卡 网卡一:供连接互联网使用网卡二:供连接内网使用(看情况,如果一张网卡足够,没必要做第二张网卡) 工具: net-to

[转帖]

https://cloud.tencent.com/developer/article/2168105?areaSource=104001.13&traceId=zcVNsKTUApF9rNJSkcCbB 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻

[转帖]ISV 、OSV、 SIG 概念

ISV 、OSV、 SIG 概念 2022-10-14 12:29530原创大杂烩 本文链接:https://www.cndba.cn/dave/article/108699 1. ISV: Independent Software Vendors “独立软件开发商”,特指专门从事软件的开发、生产、

[转帖]Redis 7 参数 修改 说明

2022-06-16 14:491800原创Redis 本文链接:https://www.cndba.cn/dave/article/108066 在之前的博客我们介绍了Redis 7 的安装和配置,如下: Linux 7.8 平台 Redis 7 安装并配置开机自启动 操作手册https://ww

[转帖]HTTPS中间人攻击原理

https://www.zhihu.com/people/bei-ji-85/posts 背景 前一段时间,公司北京地区上线了一个HTTPS防火墙,用来监听HTTPS流量。防火墙上线之前,邮件通知给管理层,我从我老大那里听说这个事情的时候,说这个有风险,然后意外地发现,很多人原来都不知道HTTPS防