由浅入深介绍 Python Websocket 编程

2023-05-16

目录

    • 1. 为什么使用 Websocket ?
      • 1.1 websocket 协议简介
      • 1.2 基本原理
    • 2. 如何用 Python 搭建 Websocket 服务
      • 2.1 安装websockets包
      • 2.2 编写 server 端代码
    • 3. Python websocket 客户端实现代码
    • 4. Javascript websocket 客户端实现代码
    • 5. 测试websocket
    • 6. 服务器向客户端广播消息


1. 为什么使用 Websocket ?

1.1 websocket 协议简介

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

适用场景

  • html页面实时更新, 客户端的html页面内,用` javascript` 与 server 建立websocket连接,实现页面内容的实时更新。Websocket 非常适合网页游戏、聊天、证券交易等实时应用。
  • 要求保持长连接的实时通信的应用场景。 如基于位置的服务应用,物联网,多方协作软件,在线教育,带社交属性的手机APP等。

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

1.2 基本原理

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

在这里插入图片描述

WebSocket 握手请求消息示例::

GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket

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

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-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端的主要方法:

  • recv() 收消息
  • send() 发送消息
  • serve() 创建 server 对象

实现步骤:

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

websocket 地址格式:

  • ws://主机地址:端口号
  • wss://主机地址:端口号, wss表示此连接为https 连接。

下面是具体的代码 server.py

#!/usr/bin/python3
# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求
import asyncio
import websockets
from datetime import datetime


async 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 forever

if __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:9999
Connected to ws://localhost:9999.
> hello, world
< Data received as "hello, world".  time: 2023-04-01 09:24:14.787357
Connection closed: 1000 (OK).

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

3. Python websocket 客户端实现代码

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

  • connect() 建立与服务器的连接
  • recv(), send() 收发消息
  • close() 显式地关闭连接

下面看一下示例 client.py

import asyncio
import websockets
import time


async 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个简单的例子来演示,实现步骤:

  • 保存每个 websocket 客户连接
  • 向每个客户发送消息

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

#!/usr/bin/python3
# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求
import asyncio
import websockets
from datetime import datetime

CONNECTIONS = set()

async def send(websocket, message):
    try:
        await websocket.send(message)
    except websockets.ConnectionClosed:
        pass

async def broadcast(message=""): 
    # 向队列中的每个连接发送消息, 广播10次
    for i in range(0,10):
	    message = f"Broadcast: New user joined, now time is {datetime.now()}"
	    if CONNECTIONS :  # asyncio.wait doesn't accept an empty list
	        await asyncio.wait([
	            asyncio.create_task(send(websocket, message))
	            for websocket in CONNECTIONS 
	        ])
	    await asyncio.sleep(30)   #每次广播间隔
        
async def handler(websocket):
    CONNECTIONS.add(websocket)   # 保存客户连接至集合
    try:
        # do other things
        await websocket.wait_closed()        
    finally:
        CONNECTIONS.remove(websocket)

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())

注: 本例broadcast() 方法每30秒,就向全部用户发送广播。实际应用时可以保持永久循环

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

由浅入深介绍 Python Websocket 编程 的相关文章

  • HEXO部署博客内容到github报错

    今天在更新部署博客内容时出现了如下报错 xff1a 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 6
  • GO通过HTTP获取API的返回值(response)

    目录 net httpnet url net http span class token keyword import span span class token string 34 net http 34 span Go语言提供了HTTP
  • STM32F103学习笔记(2.3)——读GPIO 按键

    为了读取引脚的高低电平 xff0c 就需要将引脚配置成输入模式 xff0c 并读取IDR寄存器 目录 寄存器配置 端口配置低寄存器 GPIOx CRL x 61 A E 端口输入数据寄存器 GPIOx IDR x 61 A E 按键点灯 寄
  • Windows系统下,Ubuntu安装至移动硬盘(简单分析与详细安装教程)

    前期说明 博主因学业要求 xff0c 需要同时使用Windows系统与Linux系统 xff0c 故而考虑安装双系统 但个人电脑硬盘仅剩100G左右大小 xff0c 安装双系统可能导致硬盘容量不足 xff0c 恰好博主手中有个空闲的移动硬盘
  • QT开发学习4(远程调试 Qt 程序)

    2 5 1 rsync 方式 Qt 远程调试 在 Qt Creator 中默认情况下 xff0c 会使用 sftp 或 rsync 发送程序到板卡 由于正点原子 I MX6 U 出厂 Qt 文件系统 xff08 文件系统 V1 9 及之后的
  • 使用 python requests 模块发送 http 请求及接收响应

    内容概要 如何构建GET 与 POST request 请求消息对 request 的header query string message body 定制化http header参数 content type 的设置分析request r
  • 汇编.section和.text以及入口地址解释

    section data 汇编程序中以 开头的名称并不是指令的助记符 xff0c 不会被翻译成机器指令 xff0c 而是给汇编器一些特殊指示 xff0c 称为汇编指示 xff08 Assembler Directive xff09 或伪操作
  • Linux - 配置Linux用户的环境变量- Anaconda3的环境变量配置

    目录 临时生效变量环境变量的分类 xff08 永久生效 xff09 如何让某个命令永久生效环境变量配置文件的运行顺序参考链接 Linux 操作系统的环境变量 xff0c 看似很复杂 xff0c 其实不然 我们通常用到的Windows 操作系
  • 兔子繁殖问题

    首先读懂题目 xff0c 知道运算规律后在使用斐波那契数列九很好解决啦 7 26 兔子繁殖问题 10 分 已知有一对兔子 xff0c 每个月可以生一对兔子 xff0c 而小兔子一个月后又可以生一对小兔子 比如 2月份出生的小兔子4月份可以生
  • 华为Atlas200DK环境配置指南(版本20.0.0)

    官方参考文档 https support huaweicloud com usermanual A200dk 3000 atlas200dk 02 0024 html 务必保证配置时版本 20 0 0 一致 1 配置开发环境 自己电脑 若不
  • 软件工程(速成)——第三章 需求分析

    一 需求分析 1 需求分析的概念与任务 xff1a 需求分析是软件定义时期的最后一个阶段 xff0c 它的基本任务是准确地回答 系统必须做什么 这个问题 二 分析建模与规格说明 需求分析应该建立三种模型 xff1a 数据模型 功能模型 行为
  • Pytorch 深度学习实战:视频自动打码

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 人脸识别 人脸识别是一门比较成熟的技术 它的身影随处可见 xff0c 刷脸支付 xff0c 信息审核 xff0c 监控搜索 xff0c
  • 基于深度学习的视觉目标跟踪方法

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 以前写过一个 自动驾驶中的目标跟踪 介绍 xff0c 这次重点放在深度学习和摄像头数据方面吧 先提一下以前说的那篇综述 xff1a 3
  • 递归解决赶鸭子问题,角骨定理

    一 题目分析 用递归方法设计下列各题 xff0c 并给出每道题目的递归出口 xff08 递归结束的条件 xff09 和递归表达式 同时考虑题目可否设计为非递归方法 xff0c 如果可以 xff0c 设计出非递归的算法 1 一个人赶着鸭子去每
  • 最详细ubuntu16.04安装nvidia显卡驱动(完全无经验小白教程)

    ubuntu16 04安装nvidia显卡驱动 1 禁用nouveau ubuntu 16 04默认安装了第三方开源的驱动程序nouveau xff0c 安装nvidia显卡驱动首先需要禁用nouveau xff0c 不然会碰到冲突的问题
  • 修改ssh端口重启服务报错error: Bind to port 8822 on :: failed: Permission denied

    root 64 BabyishRecent VM vi etc ssh sshd config root 64 BabyishRecent VM systemctl restart sshdJob for sshd service fail
  • Linux之iptables(一、防火墙的概念)

    Linux之iptables 一 防火墙的概念 防火墙的概念 一 安全技术 入侵检测与管理系统 xff08 Intrusion Detection Systems xff09 xff1a 特点是不阻断任何网络访问 xff0c 量化 定位来自
  • Python调用海康SDK对接摄像机

    以前做过的项目都是通过 ffmpeg c 43 43 来捕获摄像机的 RSTP 视频流来处理视频帧 xff0c 抽空看了一下海康的SDK说明 xff0c 使用 python ctypes方式a实现了对海康SDK DLL的调用 可以进行视频预
  • 数码管点亮顺序——有错请纠正

    找了半天没有找到 xff0c 自己试了几个数试出来了 xff0c 记这个顺序图比记编码表要快些
  • css-input的美化

    原装input很丑陋 xff0c 我们需要人工对其进行装饰才能好看哦 xff01 首先取消选中时的蓝色外边框 xff1a outline style none 若你想取消外边框 xff1a border xff1a 0 或 border x

随机推荐

  • echarts-横向柱状图的左侧文字左对齐设置

    在需要左对齐的Y轴中这样设置 xff0c 设置完后会发现 xff0c 文字跟圆柱重合覆盖 xff08 跟你需要的位置有区别 xff09 yAxis axisLabel margin 80 textStyle align 39 left 39
  • 12108 - Extraordinarily Tired Students(特别困的学生)

    题目 xff1a When a student is too tired he can t help sleeping in class even if his favorite teacher is right here in front
  • 1211 Problem C 营救

    营救 题目描述 铁塔尼号遇险了 xff01 他发出了求救信号 距离最近的哥伦比亚号收到了讯息 xff0c 时间就是生命 xff0c 必须尽快赶到那里 通过侦测 xff0c 哥伦比亚号获取了一张海洋图 这张图将海洋部分分化成n n个比较小的单
  • JAVA: toCharArray()类 将字符串转为数组

    public class Demo public static void main String args String str 61 34 helloworld 34 char data 61 str toCharArray 将字符串转为
  • 能赢吗?

    Description 有一堆石子 xff0c 总共有n枚 xff0c 两人轮流拿 xff0c 最少拿一枚 xff0c 最多拿k枚 xff0c 拿到最后一枚的人获胜 先手拿的人可以保证自己必胜吗 xff1f Input 第一行输入一个整数T
  • python e指数函数,常用的e指数代码

    在 python中 xff0c 有一种函数叫做e指数函数 xff08 exponential function xff09 xff0c 它的名称非常的直接 xff0c 是我们在进行数值计算时经常用到的一种函数 下面就让我们一起来学习一下这种
  • 栈的概念及性质

    栈的基本概念 栈的定义 栈是一种只能在一端进行插入或删除的线性表 其中插入被称作进栈 xff0c 删除被称作出栈 允许进行插入或删除操作的一端被称为栈顶 xff0c 另一段被称为栈底 xff0c 栈底固定不变 其中 xff0c 栈顶由一个称
  • python requests post 使用方法

    使用python模拟浏览器发送post请求 span class token keyword import span requests 1 格式request post xff1a request span class token punc
  • 各类Python项目的项目结构及代码组织最佳实践

    1 了解Python项目文件组织结构非常重要 为什么要掌握pythob项目结构 xff1f 优秀的程序员都使用规范的项目代码结构 xff0c 了解这些好的习惯方式 xff0c 能帮助你快速读懂代码如果项目是几个人合作开发 xff0c 好的代
  • Python简单的位运算

    位运算 程序中的数在计算机内存中都是以二进制的形式存在的 xff0c 位运算就是直接对整数在内存中对应的二进制位进行操作 位运算分为 6 种如下 xff1a 1 按位与 按位与运算符 xff1a 参与运算的两个值 如果两个相应位都为1 则该
  • 【Linux】WLAN接口桥接

    一 内核补丁 因为Linux内核会在注册特定设备时将会将dev gt priv flags置为IFF DONT BRIDGE xff0c 所以现还不支持sta p2p client adhoc等无线接口加入到桥接中去的 xff0c 所以要支
  • Python学习小记-爬虫基础例子之抓取热门游戏排行榜-2020-3-2

    span class token keyword import span urllib span class token punctuation span request span class token keyword import sp
  • 《A Survey on Aspect-Based Sentiment Analysis: Tasks, Methods, and Challenges》阅读笔记

    忙活了一阵子后 xff0c 现在终于有空研究一下目前如火如荼的ABSA了 xff0c 当然 xff0c 还是先从综述出发 A Survey on Aspect Based Sentiment Analysis Tasks Methods a
  • A problem has occurred and the system can‘t recover问题的解决

    A problem has occurred and the system can 39 t recover问题的解决 问题描述解决方法参考博客 问题描述 启动后无法进入图形界面 xff0c 出现如下报错内容 按 ctrl 43 alt 4
  • 安装:WSL2(Ubuntu18.04)+miniconda3+mysql数据库+windows pycharm连接wsl

    一 WSL2 xff08 Ubuntu18 04安装 xff09 1 开启 适用于Linux的Windows子系统 找到控制面板 程序和功能 启用或关闭Windows功能 xff0c 选中 适用于Linux的Windows子系统 和 虚拟机
  • 【Python入门】:字典与集合

    Problems span class token number 1 span span class token punctuation span 创建一个通讯录 xff0c 步骤如下 xff0c 请根据步骤完成以下操作 xff1a spa
  • 【Python入门】:函数1

    Problems span class token number 1 span span class token punctuation span 编写函数showMsg span class token punctuation span
  • 【Python】@property私有属性的控制和保护

    64 property的使用 xff1a 对属性的控制和保护 一 保护变量 xff0c 防止被修改 64 property的首要目的是在访问私有变量时 xff0c 保护变量不被随意修改 span class token keyword cl
  • 【Python入门】:函数2

    Problems Source Code Output span class token number 318 span span class token number 321 span span class token number 19
  • 由浅入深介绍 Python Websocket 编程

    目录 1 为什么使用 Websocket 1 1 websocket 协议简介1 2 基本原理 2 如何用 Python 搭建 Websocket 服务2 1 安装websockets包2 2 编写 server 端代码 3 Python