简易屏幕共享工具-基于WebSocket
前面写了两个简单的屏幕共享工具,不过那只是为了验证通过截屏的方式是否可行,因为通常手动截屏的频率很低,而对于视频来说它的帧率要求就很高了,至少要一秒30帧率左右。所以,经过实际的截屏工具验证,我了解了几个Python截屏库的特点和限制。例如,多数截屏库都不支持很高的截屏速度,并且截屏是典型的 CPU 密集任务(我尝试使用多线程截屏,发现速度更慢了,之后有时间我也会把这一点整理成文章发出来)。
所以,我的初始的想法其实是基于 WebSocket 来实现的。现在,就让我们对先前的代码进行重构,采用 WebSocket 来传输图片数据。不过我这里没有使用到它的双向传输的特性,只是将原来 HTTP 传输的图片换成通过 WebSocket 来传输了。不过这里后续还有很多东西可以开发,如果有时间的话,也可以基于这个做一些有趣的东西。
演示
我这个笔记本的性能可能不太行,我只要打开视频帧率就降低了很多,哈哈。
截取播放B站视频

截取摄像头画面
这样甚至可以远程共享画面了,如果两个人都布置一个,就可以各自看到对话了(不过没有声音,且效率低下,可能也就只能在局域网使用),不过这样它是相当于从服务器的地方获取的数据,而我们平时使用的视频通话工具都是从客户端获取的数据。
而且页面越多,帧率越低,这里可能要优化一下或者它就是这么累赘,只能个人使用。

说明
注意,这里的测试环境是 Windows,因为有些库依赖于 Windows 提供的特性,所以需要在 Windows 上运行它。在程序启动时,它会开启一个截屏的线程,不断去获取屏幕的截屏,如果有用户访问,它就会通过 WebSocket 连接,把获取的屏幕截图数据传送给前端,前端的逻辑就是将它绘制在 canvas 上,并添加帧率显示。
注意:这部分前端的代码是 AI 生成,对于验证小功能来说,AI 真是太完美了。而且,其实这整个部分都可以让 AI 来做,但是具体是哪些的组合还是自己选择的,毕竟每个人的偏好和技术栈不同。
代码
所有的代码都在这里了,大概60行代码,我把前端压缩成一行代码了。如果要运行代码先要安装 flask, flask_sock, pillow, dxcam 库。
import time
from flask import Flask
from flask_sock import Sock
from io import BytesIO
from PIL import Image
import dxcam# 创建应用
app = Flask(__name__)
sockets = Sock(app)
# 整个应用只创建一个即可
camera = dxcam.create(device_idx=0, output_idx=1) # output_idx 0 是第一块屏幕,1 是第二块屏幕
camera.start(target_fps=60, video_mode=True)
JPEG_QUALITY = 80 # 默认的jpeg图片质量,越高需要的计算量越大,同时越清晰# 直接前后端写一起了,这个只是一个演示的demo
INDEX_HTML = """
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Screen Sharing</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f0f0f0; } canvas { border: 1px solid black; } </style> </head> <body> <canvas id="screenCanvas" width="960" height="540"></canvas> <script> const canvas = document.getElementById('screenCanvas'); const ctx = canvas.getContext('2d'); const ws = new WebSocket('ws://'+window.location.host+'/remote_desktop'); ws.onopen = () => { console.log("WebSocket connected"); }; ws.onerror = (event) => { console.error("WebSocket error:", event); }; let lastFrameTime = performance.now(); let frameCount = 0; let fps = 0; ws.onmessage = (event) => { const image = new Image(); image.src = URL.createObjectURL(event.data); image.onload = () => { ctx.drawImage(image, 0, 0, canvas.width, canvas.height); frameCount++; const now = performance.now(); const elapsed = now - lastFrameTime; if (elapsed >= 1000) { fps = frameCount / (elapsed / 1000); frameCount = 0; lastFrameTime = now; } displayFPS(); }; }; function displayFPS() { ctx.font = '30px Arial'; ctx.fillStyle = 'red'; ctx.fillText(`FPS: ${Math.round(fps)}`, 50, 50); } </script> </body> </html>
"""@app.route('/', methods=['GET'])
def index():"""简单的前端"""return INDEX_HTML@sockets.route('/remote_desktop')
def get_desktop(ws):"""获取一帧图片,并发送给前端"""buffer = BytesIO()fps = 0 # 计算后端生成的帧率frame_count = 0last_frame_time = time.perf_counter()while True:reset_buffer(buffer) # 每次重置buffer,方便复用img_data = get_frame(buffer)frame_count += 1elapsed = time.perf_counter() - last_frame_timeif elapsed >= 1:fps = frame_count // elapsedlast_frame_time = time.perf_counter()frame_count = 0print("backend real frame fps: ", fps)ws.send(img_data)def get_frame(buffer):"""获取一帧,然后处理成jpeg并返回二进制数据"""image_array = camera.get_latest_frame()Image.fromarray(image_array).save(buffer, format="JPEG", quality=JPEG_QUALITY)return buffer.getvalue()def reset_buffer(buffer):# 重置buffer,方便复用buffer.truncate(0)buffer.seek(0)if __name__ == '__main__': print("remote desktop server starting...")app.run("0.0.0.0", 9000)
相关文章:
简易屏幕共享工具-基于WebSocket
前面写了两个简单的屏幕共享工具,不过那只是为了验证通过截屏的方式是否可行,因为通常手动截屏的频率很低,而对于视频来说它的帧率要求就很高了,至少要一秒30帧率左右。所以,经过实际的截屏工具验证,我了解…...
Redis——主从复制模式
文章目录 1. 引入2. 主从复制模式2.1 概念2.2 配置2.3 原理2.3.1 建立连接阶段2.3.2 命令传播阶段2.3.3 心跳检测机制2.3.4 部分重同步机制(1) 主节点通过 复制积压缓冲区 记录写命令(2) 主节点通过 复制偏移量 判断从节点是否满足执行部分重同步的条件(3) 执行部分重同步操作 …...
简历_熟悉缓存高并发场景处理方法,如缓存穿透、缓存击穿、缓存雪崩
系列博客目录 文章目录 系列博客目录1.缓存穿透总结 2.缓存雪崩3.缓存击穿代码总结 1.缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种: 缓存空对…...
阿里云电商平台用户行为分析与人群画像系统设计与实现
通过在阿里云(https://baike.baidu.com/item/%E9%98%BF%E9%87%8C%E4%BA%91/297128)上构建包含数据源层、数据存储层、数据处理层、数据分析层和数据应用层的系统架构,并设计合理的数据模型、ETL流程、数据质量与性能监控机制以及安全与合规性…...
Go语言的 的输入/输出流(I/O Streams)核心知识
Go语言的输入/输出流(I/O Streams)核心知识 前言 Go语言是一种现代编程语言,因其高效性、简洁性及强大的并发支持而受到开发者的喜爱。在开发应用程序时,输入/输出(I/O)操作是一个不可或缺的部分。无论是…...
57.在 Vue 3 中使用 OpenLayers 点击选择 Feature 设置特定颜色
在 Web 开发中,地图应用是非常常见的需求,而 OpenLayers 是一个非常强大的地图库,它提供了丰富的地图操作功能。今天,我们将一起学习如何在 Vue 3 中结合 OpenLayers 使用点击事件来选择地图上的 Feature,并设置特定的…...
数据结构C语言描述8(图文结合)--哈希、哈希冲突、开放地址法、链地址法等实现
前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…...
自动化立体库安全使用管理制度完整版
导语 大家好,我是社长,老K。专注分享智能制造和智能仓储物流等内容。欢迎大家到本文底部评论区留言。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料,请球友到知识星球【智能仓储物流技术研习社】自行下载。 以下是《…...
云打印之拼多多打印组件交互协议
拼多多打印组件交互协议相关介绍如下: 1、打印组件下载地址 http://meta.pinduoduo.com/api/one/app/v1/lateststable?appIdcom.xunmeng.pddprint&platformwindows&subTypemain 2、socket连接端口 如果是http的话,端口是5000 socket new …...
TCP 演进之路:软硬件跷跷板与新征程
今天依旧是与 TCP 相关的一个短评。 先看软硬件间的胶着。晶体管诞生以来,硬件一直在突飞猛进发展,后来这个事被摩尔定律正则化,人们开始可以预测未来,但即便如此,软件依然跟不上来,不过几年,老…...
React最小状态管理Jotai
Jotai 状态管理 1. 简介 Jotai 是一个基于原子 atom 概念的 React 状态管理库,它提供了简单且灵活的方式来管理应用状态, 而且非常轻量, 大厂用的非常多。 JotaiRedux适合单个页面,多次用到的属性适合全局公共属性超级轻量(与use…...
计算机网络 —— 网络编程(TCP)
计算机网络 —— 网络编程(TCP) TCP和UDP的区别TCP (Transmission Control Protocol)UDP (User Datagram Protocol) 前期准备listen (服务端)函数原型返回值使用示例注意事项 accpect (服务端)函数原型返回…...
字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化
字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化 字玩FontPlayer是笔者开源的一款字体设计工具,使用Vue3 ElementUI开发,源代码: github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer …...
RabbitMQ案例
1. 导入依赖 <!--AMQP依赖,包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 发送消息 注入RabbitTemplate Autowired RabbitT…...
智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之13 方案再探之4:特定于领域的模板 之 div模型(完整版)
前景提要 整个“方案再探”篇 围绕着如何将项目附件文档中Part 1 部分中给出的零散问题讨论整理、重组为一个结构化的设计文档。为此提出了讨论题目: 特定于领域的模板--一个三套接的hoc结构 它是本项目actors 的剧本原型。其地位: 祖传代码脚本模板…...
WebRtc02:WebRtc架构、目录结构、运行机制
整体架构 WebRtc主要分为三层: CAPI层:外层调用Session管理核心层:包括视频引擎、音频引擎、网络传输 可由使用者重写视频引擎:编解码器、视频缓存、视频增强音频引擎:编解码器、音频缓存、回音消除、降噪传输&#x…...
数据结构复习 (顺序查找,对半查找,斐波那契查找,插值查找,分块查找)
查找(检索): 定义:从给定的数据中找到对应的K 1,顺序查找: O(n)的从前向后的遍历 2,对半查找,要求有序 从中间开始查找,每次检查中间的是否正确,不正确就…...
el-input输入框需要支持多输入,最后传输给后台的字段值以逗号分割
需求:一个输入框字段需要支持多次输入,最后传输给后台的字段值以逗号分割 解决方案:结合了el-tag组件的动态编辑标签 那块的代码 //子组件 <template><div class"input-multiple-box" idinputMultipleBox><div>…...
C# 枚举格式字符串
总目录 前言 当前文章为 C# 中的格式设置(格式化字符串) 大全 中的一个小章节。 一、概述 1. 基本信息 可以使用 Enum.ToString 方法,新建表示枚举成员的数字值、十六进制值或字符串值的字符串对象。枚举格式说明符不区分大小写。 二、自定义数字格式说明符详解…...
【51单片机-零基础chapter1】
安装软件(配套的有,不多赘述) 1.管理员身份运行keil和破解软件kegen 将CID代码复制粘贴到 一定要管理员方式,不然会error 插入板子 我的电脑,管理 1.如果是拯救者,查看端口,如果没有则显示隐藏 2.苹果不知道,好像不可以 3.其他电脑在"其他设备找" (注:本人在校已…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
