前言
最近项目需求涉及到websocket的技术使用,同时补充一下自身这块的知识。本章都是个人使用经验总结。如有异议,欢迎大家留言...
WebSocket的出现,使得浏览器具备了实时双向通信的能力。本文介绍将 WebSocket如何建立连接、交换数据的细节,以及数据帧的格式。
首先介绍一下 websocket
1. WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。
2. 换句话说:HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。
1. WebSocket可以在浏览器里使用
2. 支持双向通信
3. 使用很简单
对比 http 协议
- websocket 支持双向通信,更灵活,更高效,可扩展性更好。
- 支持双向通信,实时性更强。
- 更好的二进制支持。
- 较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
- 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
- http 是单向的,客户端发送请求,服务器发送响应。
- http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能发送信息。
- http链接分为短链接,长链接。(客户端是主动的,服务器是被动的)
如何建立连接:(案列演示)
# 服务端代码 django作为服务端
1. 创建一个apis.py文件
from django.http import JsonResponse
from dwebsocket.decorators import accept_websocket
@accept_websocket
def dome_app01(request):
message = request.websocket.wait()
print("打印客户端请求信息: ", message)
request.websocket.send(json.dumps({"code": "001"})) # 返回相应数据
# return JsonResponse({"code": "001"}) # 返回相应数据
# 客户端代码 脚本文件.py
import json
import asyncio
import websockets
# 客户端主逻辑
async def main_logic():
async with websockets.connect('ws://127.0.0.1:8000/app01/dome-app01/', ping_timeout=10) as websocket:
await websocket.send(json.dumps({"code": "01", "msg": "hhhh"}))
response_str = await websocket.recv()
print("接受服务端返回信息: ", response_str)
asyncio.get_event_loop().run_until_complete(main_logic())
数据帧格式
- 客户端、服务端数据的交换,离不开数据帧格式的定义。因此,在实际k讲解数据交换之前,我们先来看下WebSocket的数据帧格式。
- WebSocket客户端、服务端通信的最小单位是帧(frame),由1个或多个帧组成一条完整的消息(message)。
- 发送端:将消息切割成多个帧,并发送给服务端;
- 接收端:接收消息帧,并将关联的帧重新组装成完整的消息
数据传递
- WebSocket客户端、服务端建立连接后,后续的操作都是基于数据帧的传递。
- WebSocket 根据
opcode
来区分操作的类型。比如0x8
表示断开连接,0x0
-0x2
表示数据交互。
- 数据分片
- WebSocket的每条消息可能被切分成多个数据帧。当WebSocket的接收方收到一个数据帧时,会根据
FIN
的值来判断,是否已经收到消息的最后一个数据帧。
- FIN=1表示当前数据帧为消息的最后一个数据帧,此时接收方已经收到完整的消息,可以对消息进行处理。FIN=0,则接收方还需要继续监听接收其余的数据帧。
- 此外,
opcode
在数据交换的场景下,表示的是数据的类型。0x01
表示文本,0x02
表示二进制。而0x00
比较特殊,表示延续帧(continuation frame),顾名思义,就是完整消息对应的数据帧还没接收完。
Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!