文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

由浅入深介绍 Python Websocket 编程

2023-09-04 12:29

关注

目录


1. 为什么使用 Websocket ?

1.1 websocket 协议简介

Websocket协议是对http的改进,可以实现client 与 server之间的双向通信; websocket连接一旦建立就始终保持,直到client或server 中断连接,弥补了http无法保持长连接的不足,方便了客户端应用与服务器之间实时通信。

适用场景

实时更新数据场景,为什么不使用AJAX?
AJAX 采用http, 如果要实时更新页面,则需要不断地发送http 请求,无论是否有数据更新,产生大量冗余通信流量。而websocket是长连接双向通信,有数据更新时,服务器向客户机发送通知。

1.2 基本原理

基于TCP,一次握手就能建立连接,支持双向通信,可保持长连接。

在这里插入图片描述

WebSocket 握手请求消息示例::

GET /chat HTTP/1.1Host: normal-website.comSec-WebSocket-Version: 13Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==Connection: keep-alive, UpgradeCookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2Upgrade: websocket

如果 Server 接收连接,返回响应

HTTP/1.1 101 Switching ProtocolsConnection: UpgradeUpgrade: websocketSec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=

响应码为101,表示切换为websocket 协议。

websocket 已得到主流浏览器,各编程语言的广泛支持,基本都提供了WebSocket高阶编程API,在一般场合下,可以替代socket低阶函数编程。python 提供了更简洁的编程实现方式。下面展示了实例代码方式,说明如何开发 Python websocket 服务器代码,python websocket 客户端, 以及javascript websocket 代码。

2. 如何用 Python 搭建 Websocket 服务

python 第3方库 websockets 提供了websocket 实现框架,支持asyncio, 性能强大,稳定性好,可以用于生产环境。

2.1 安装websockets包

pip install websockets

2.2 编写 server 端代码

Websocket服务端代码是面向多用户的长连接,因此本文采用了python3.7 版本的 asyncio 异步方式编写 websocket server 代码。

服务端也可使用 ThreadPoolExecutor 线程池方式同时处理多连接的场景,用户较多时,性能明显不如asyncio异步方式。

websockets 模块 server端的主要方法:

实现步骤:

  1. 编写websocket 异步任务处理函数handler
  2. 创建1个websocket server 对象
  3. 异步运行 server对象

websocket 地址格式:

下面是具体的代码 server.py

#!/usr/bin/python3# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求import asyncioimport websocketsfrom datetime import datetimeasync def handler(websocket):    data = await websocket.recv()    reply = f"Data received as \"{data}\".  time: {datetime.now()}"    print(reply)    await websocket.send(reply)    print("Send reply")async def main():    async with websockets.serve(handler, "localhost", 9999):        await asyncio.Future()  # run foreverif __name__ == "__main__":    asyncio.run(main())

服务端handler函数代码还有1种写法,适用性更好。

async def handler(websocket):    async for message in websocket:    reply = f"Data received as \"{message}\".  time: {datetime.now()}"    print(reply)        await websocket.send(reply)

Websocket协议本身有心跳机制、连接检测机制,服务端无须关心客户端状态,一旦有异常,会自动断开连接。

Websockets提供了交互式测试命令,现在可以快速测试一下服务端是否能正常工作:
(1) 启动服务器: python server.py
(2) 通过命令行连接服务端,并向发送hello, world 消息,可以看到,收到了服务器的响应。

D:\workplace\python\projects\websock>python -m websockets ws://localhost:9999Connected to ws://localhost:9999.> hello, world< Data received as "hello, world".  time: 2023-04-01 09:24:14.787357Connection closed: 1000 (OK).

当然实际应用时,应按下面步骤来编写客户端代码。

3. Python websocket 客户端实现代码

websockets 客户端提供的主要方法:

下面看一下示例 client.py

import asyncioimport websocketsimport timeasync def ws_client(url):    for i in range(1, 40):        async with websockets.connect(url) as websocket:            await websocket.send("Hello, I am PyPy.")            response = await websocket.recv()        print(response)        time.sleep(1)asyncio.run(ws_client('ws://localhost:9999'))

4. Javascript websocket 客户端实现代码

目前主流的浏览器都支持websocket协议。

Javascript websocket 对象的主要属性与方法:
请参考菜鸟教程的这篇文章:https://www.runoob.com/html/html5-websocket.html

示例代码: client.html

<!DOCTYPE HTML><html><head>    <meta charset="utf-8">    <title>websocket demo</title>  <meta name="viewport" content="width=device-width, initial-scale=1">  <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css"><script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script><script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>  <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>    <script type="text/javascript">        function WebSocketTest() {            text = document.getElementById("div_text");            if ("WebSocket" in window) {                // 打开一个 web socket                var ws = new WebSocket("ws://localhost:9999/handler");                ws.onopen = function () {                    // Web Socket 已连接上,使用 send() 方法发送数据                    ws.send("Javscript发送的数据");                    text.innerHTML = "数据发送中...";                    alert("数据发送中...");                };                ws.onmessage = function (evt) {                    var received_msg = evt.data;                    text.innerHTML = "收到的数据:" + received_msg;                    alert("数据已接收...");                };                ws.onclose = function () {                    // 关闭 websocket                    text.innerHTML = "连接已关闭...";                    alert("连接已关闭...");                };            }            else {                // 浏览器不支持 WebSocket                alert("您的浏览器不支持 WebSocket!");            }        }    </script></head><body>    <div class="col-md-6 m-5 p-2" id="div_ws">        <a class="btn btn-primary" href="javascript:WebSocketTest()">连接WebSocket</a>    </div>    <div class="col-md-6 border border-primary mx-5 p-2 " id="div_text" style="margin:20px;height:100px;">        display communicate text    </div></body></html>

5. 测试websocket

上述3个文件都放在同1个目录下,打开两个终端窗口,先运行server.py, 再运行 client,py。
Output结果
在这里插入图片描述
在chrome 或edge 中运行client.html, 可以看到websocket 连接建立,发送,接收,关闭各阶段的状态。
在这里插入图片描述
能够看到,服务器与客户端之间的通信是双向的,而且是长连接,客户端断开后,服务器仍然保持侦听状态,而且不需要accept操作。websocket发送、接收文件也不需要 socket 对发送窗口 buffer 进行控制,因此是 socket 开发非常好的替代。

注:Python异步websocket服务器最终性能与代码质量、服务器硬件、网络等紧密相关,可以使用 Websocket-benchmarker 测试工具来测试服务器。

6. 服务器向客户端广播消息

websockets 模块支持向所有连接的客户广播消息,
用1个简单的例子来演示,实现步骤:

将前面的server,.py 代码修改后如下:

#!/usr/bin/python3# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求import asyncioimport websocketsfrom datetime import datetime# Set of connected clientsconnected_clients = set()async def handler(websocket, path):    # Add the client to the connected clients set    connected_clients.add(websocket)        try:        # Keep listening for incoming messages from the client        async for message in websocket:            # Broadcast the message to all connected clients            await broadcast(message)    finally:        connected_clients.remove(websocket)         async def broadcast(message):    # Broadcast the message to all connected clients    for client in connected_clients:        await client.send(message)async def main():    async with websockets.serve(handler, "localhost", 9998):        await asyncio.Future()  # run forever        loop = asyncio.get_running_loop() #获取当前event_loop对象        loop.create_task(broadcast())     # 添加新的异步广播任务if __name__ == "__main__":    asyncio.run(main())

本例中,当服务器收到1条消息时,会广播给所有用户。

来源地址:https://blog.csdn.net/captain5339/article/details/128212124

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯