1. websocket 基本理论
1.1 WebSocket 是什么
WebSocket 是一种在单个 TCP 连接
上进行全双工通信
的协议。它允许客户端和服务器之间进行实时、双向
的通信,而无需进行 HTTP 请求/响应的循环。
WSGI(Web Server Gateway Interface)服务器是用于运行 Python Web 应用程序的标准接口。它定义了 Web 服务器与 Python Web 应用程序之间
通信的协议
,允许不同的 Web 服务器运行相同的 Python Web 应用程序。
特点
- 全双工通信: 客户端和服务器可以同时发送和接收数据,而无需等待对方完成发送。
- 低延迟: WebSocket 连接的延迟比 HTTP 连接低得多,因此可以用于实时通信。
- 高效: WebSocket 连接比 HTTP 连接更有效率,因为它们不需要在每次通信时都建立新的连接。
- 可扩展: WebSocket 连接可以处理大量的数据,因此可以用于高性能的应用程序。
用途
WebSocket 接口通常用于以下场景:
- 实时聊天: WebSocket 接口可以用于实现实时聊天应用程序,例如 WhatsApp、Facebook Messenger 等。
- 实时数据: WebSocket 接口可以用于实时传输数据,例如股票价格、体育比分等。
- 游戏: WebSocket 接口可以用于实现多人游戏,例如 Fortnite、Apex Legends 等。
- 协作工具: WebSocket 接口可以用于实现协作工具,例如 Google Docs、Trello 等。
示例
以下是一个使用 WebSocket 连接的简单示例:
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print(f"收到来自 {name} 的消息")
await websocket.send(f"你好,{name}!")
start_server = websockets.serve(hello, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
这个示例代码创建一个 WebSocket 服务器,它监听来自 8765 端口的连接。当收到客户端连接时,服务器会发送一条 “你好,{name}!” 的消息给客户端。
1.2 双工通信的现有技术
1.2.1 轮询
轮询可以定义为一种方法,无论传输中存在什么数据,它都执行周期性请求
。周期性请求以同步方式发送。客户端以指定的时间间隔向服务器发出周期性请求
1.2.2 长轮询
长轮询,顾名思义,包括与轮询类似的技术。客户端和服务器保持连接处于活动状态
,直到获取某些数据或发生超时
。如果由于某种原因连接丢失,客户端可以重新开始并执行顺序请求。 长轮询只不过是轮询过程的性能改进,但持续的请求可能会减慢该过程。
1.2.3 流媒体
它被认为是实时数据传输的最佳选择。服务器保持与客户端的连接打开和活动
,直到获取所需的数据
为止。在这种情况下,连接被称为无限期打开。流媒体包含 HTTP 标头,这会增加文件大小,从而增加延迟。这可以被认为是一个主要缺点。
1.2.4 AJAX
AJAX 基于 Javascript 的 XmlHttpRequest 对象。它是异步 Javascript 和 XML 的缩写形式。 XmlHttpRequest 对象允许执行 Javascript,而无需重新加载整个网页。 AJAX 仅发送和接收网页的一部分
。
与 Web Sockets 相比,AJAX 的主要缺点是 :
- 它们发送 HTTP 标头,这使得总大小更大
- 通信是半双工的
- Web 服务器消耗更多资源
1.2.5 HTML5
HTML5 是用于开发和设计 Web 应用程序的强大框架。主要支柱包括标记、CSS3 和 Javascript API。
1.3 websocket建立连接流程
客户端通过称为 Web Socket 握手的过程建立连接。 该过程从客户端向服务器发送常规 HTTP 请求开始。 请求升级标头。在这个请求中,它通知服务器该请求是针对Web Socket连接的。 Web Socket URL 使用 ws 方案。它们还用于安全 Web Socket 连接,相当于 HTTP
初始请求标头的一个简单示例:
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
1.4 为什么需要websocket
HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息
。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步JavaScript和XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。
WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高
参考资料
2. websocket的角色
为了实现客户端之间的通信,需要初始化客户端到服务器的连接。为了初始化连接,需要使用远程或本地服务器的 URL 创建 Javascript 对象。
var socket = new WebSocket(“ ws://echo.websocket.org ”);
上面提到的URL是一个公共地址,可以用于测试和实验。 websocket.org 服务器在收到消息并将其发送回客户端时始终处于运行状态。 这是确保应用程序正常运行的最重要的步骤。
2.1 websocket事件
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
2.2 WebSocket 方法
方法 | 描述 |
---|---|
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
3. 扩展知识
3.1 WSGI 服务器示例
#使用 Gunicorn 运行 Flask 应用程序
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello, world!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
gunicorn app:app
gunicorn
命令用于启动 Gunicorn WSGI 服务器。app:app
指定要运行的 Python Web 应用程序。
使用 uWSGI 运行 Django 应用程序
import django
django.setup()
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world!")
uwsgi --http :8000 --module index:index
uwsgi
命令用于启动 uWSGI WSGI 服务器。--http :8000
指定监听的端口。--module index:index
指定要运行的 Python Web 应用程序。
可以使用不同的 WSGI 服务器运行 Python Web 应用程序。Gunicorn 和 uWSGI 是两种常用的 WSGI 服务器。