WebSocket协议

WebSocket协议

当一个项目是一个互动频繁,并且有一定的即时性要求保证服务端的状态能及时同步到客户端的模块,所以如果继续基于http协议开发,那么需要通过ajax发送大量http请求,同时因为http本身属于单向通信,所以服务端无法主动发送信息提供给客户端。所以对于客户端使用来说,非常不友好,所以我们需要基于socket通信来完成这个模块的开发。当然,如果我们服务端基于socket实现tcp/ip通讯的同时,那么客户端必须也要使用socket来实现tcp/ip通讯才能正常运作。但是,浏览器客户端根本没法完成socket发送tcp/IP这个环节,或者能实现的代价也很大。所以针对上面这种业务场景,由HTML5就推出了一个针对上面场景所涉及设计出来的WebSocketj技术(协议+接口实现)。

HTML5服务器推技术:websocket协议、Worker多进程、EventSource事件源

在js中,提供了一个三个全局对象:WebSocket、Worker、EventSource 可以使用上面的三种技术。

文档:https://tools.ietf.org/html/rfc6455

一直以来,HTTP是无状态、单向通信的网络协议,即客户端请求一次,服务器回复一次,默认情况下,只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。如果想让服务器消息及时下发到客户端,需要采用类似于轮询的机制,大部分情况就是客户端通过定时器使用ajax频繁地向服务器发出请求。这样的做法效率很低,而且HTTP数据包头本身的字节量较大,浪费了大量带宽和服务器资源。

为了提高效率,让服务器消息及时下发到客户端,HTML5推出了WebSocket协议以及实现webocket协议的一整套技术。

WebSocket是一种让客户端和服务器之间能进行全双工通信(full-duplex)的应用层协议。它是HTML最新标准HTML5的一个协议规范,本质上是个基于TCP的应用层协议,它通过HTTP/HTTPS协议发送一条特殊的握手请求进行握手后创建了一个TCP连接,此后浏览器/客户端和服务器之间便可随时随地以通过此websocket连接来进行双向实时通信,且交换的数据包头信息量很小。

同时为了方便使用,HTML5提供了非常简单的操作就可以让前端开发者直接实现websocket通信,开发者只需要在支持WebSocket的浏览器中,创建webSocket对象之后,通过onopen、onmessage、onclose、onerror四个事件的实现即可处理webSocket的服务端响应,通话send即可通过websocket轻松地发送数据到服务端。

注意:websocket虽然是HTML5技术的一部分,但是websocket并非只能在浏览器或者HTML文档中才能使用,事实上在python或者C++等编程语言中只要能实现websocket协议报文,均可使用

导读:https://segmentfault.com/a/1190000014643900

image-20220217170742530

客户端请求握手报文:

GET /mofang/websocket HTTP/1.1
Host: 127.0.0.1
Origin: http://127.0.0.1:5000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==      # Sec-WebSocket-Key 是基于SHA-1随机生成,经过base64编码
Sec-WebSocket-Version: 13

服务端响应握手报文:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= # 结合客户端提供的Sec-WebSocket-Key基于固定算法计算出来的
Sec-WebSocket-Protocol: chat
                                                   # 必须后面有个空行!!!

Sec-WebSocket-Accept的计算公式:

import hashlib, base64
magic_key = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'   # 官方文档指定的固定编码!不能瞎改!
client_hkey = header_dict['Sec-WebSocket-Key']       # 表示客户端请求报文    
key = client_hkey + magic_key   # 后面拼接
hkey = base64.b64encode(hashlib.sha1(bytes(key, encoding='utf-8')).digest())
hkey_str = str(hkey)[2:30]

WebSocket与Socket的关系

他们两的关系就像Java和JavaScript,并非完全没有关系,只能说有点渊源。

Socket严格来说,其实并不是一个协议,而是为了方便开发者使用TCP或UDP协议而对TCP/IP协议进行封装出来的一组接口,是位于应用层和传输控制层之间的接口。通过Socket接口,我们可以更简单,更方便的使用TCP或UDP通信。

WebSocket是实现了浏览器与服务器的全双工通信协议,一个模拟Socket的新型应用层协议,地位和HTTP协议一样。

服务端基于Socket实现websocket协议

在python中基于socket来实现websocket服务端的方式有非常多,一种是原生的websocket协议通信模块websockets,另一种就是python-socketio,而我们现在使用的flask框架也有一个基于python-socketio模块进行了二次封装的flask-socketio模块.

官方文档:https://flask-socketio.readthedocs.io/en/latest/

注意:

因为目前还有会存在一小部分的设备或者应用是不支持websocket的.所以为了保证功能的可用性,我们使用socktio模块,但是由此带来了2个问题,必须要注意的:

  1. python服务端使用基于socketio进行通信服务,则另一端必须也是基于socketio来进行对接通信,否则无法进行通信

  2. socketio在使用上还有一个版本对应的问题, 版本不对应则无法通信.回报版本错误.

    如果使用了javascript版本socketio 1.x或者2.x版本,则python-socketio或者flask-socketio的版本必须是4.x

    如果使用了javascript版本socketio 3.x版本, 则python-socketio或者flask-socketio的版本必须是5.x.

版本对照表:

image-20211005114631731

终端下执行命令,安装:

pip install flask-socketio
# 跨域:https://flask-cors.readthedocs.io/en/latest/
pip install -U flask-cors
# websocket是异步通信,所以我们必须让服务端运行在异步模式下,所以我们选择协程模式来运行
# 方案1
pip install eventlet
# 方案2
# pip install gevent
# pip install gevent-websocket

我们当前使用的flask-socketio版本是5.x,所以记住javasctipt的socketio版本就必须是3.x以上.

posted @ 2022-04-11 12:06  寻月隐君  阅读(127)  评论(0编辑  收藏  举报