前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python实现局域网内屏幕广播的技术要点分析

Python实现局域网内屏幕广播的技术要点分析

作者头像
Python小屋屋主
发布于 2018-04-16 07:11:49
发布于 2018-04-16 07:11:49
1.5K0
举报
文章被收录于专栏:Python小屋Python小屋

为更好地保证教学质量和提高学生的学习积极性,我使用Python开发了一套课堂教学管理系统,具有在线点名、在线答疑、随机提问、在线作业管理、在线自测、在线考试、数据汇总、试卷生成、屏幕广播等功能,教师端运行界面如下图所示:

学生端运行界面如下图所示:

该系统投入使用已有4个学期,效果非常好,不仅可以满足上课的各种需要,还可以作为“Python程序设计”课程的一个完整教学案例讲给学生,适用教材包括《Python程序设计基础》(董付国编著,清华大学出版社)、《Python程序设计(第2版)》(董付国编著,清华大学出版社)、《Python可以这样学》(董付国著,清华大学出版社)。本文重点介绍屏幕广播功能的技术要点,本系统界面使用tkinter编写,使用扩展库pillow实现屏幕截图,使用socket实现屏幕截图的传送,使用多线程技术实现多客户端的数据传输,文中略去了有关标准库和扩展库的导入代码。

1、学生端启动之后,监听UDP端口1000,等待教师端发送屏幕广播指令,代码如下:

def udpListen():

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 监听本机10000端口

sock.bind(('',10000))

while True:

data, addr = sock.recvfrom(100)

# 收到服务器发来的广播指令

if data == b'startBroadCast':

threading.Thread(target=receiveBroadCast).start()

sock.close()

threading.Thread(target=udpListen).start()

2、教师端通过界面上的按钮“开始屏幕广播”给局域网内所有学生端发送指令,同时监听TCP端口10001,等待学生端的连接,然后给每一个学生端连接发送本机屏幕截图,每0.5秒刷新一次。代码如下:

broadcasting = False

def broadcast(conn):

global broadcasting

while broadcasting:

time.sleep(0.8)

image = ImageGrab.grab()

size = image.size

imageBytes = image.tobytes()

length = len(imageBytes)

# 通知将要开始发送截图

conn.send(b'*****')

fhead = struct.pack('I32sI',

length,

str(size).encode(),

len(str(size).encode()))

conn.send(fhead)

conn.send(imageBytes)

else:

conn.send(b'#####')

conn.close()

def broadcastMain():

'''广播屏幕截图的主线程函数'''

global sockBroadCast

sockBroadCast = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sockBroadCast.bind(('', 10001))

sockBroadCast.listen(150)

while broadcasting:

try:

conn, addr = sockBroadCast.accept()

except:

return

threading.Thread(target=broadcast, args=(conn,)).start()

else:

sockBroadCast.close()

def onbuttonStartBroadCastClick():

global broadcasting

broadcasting = True

# 启动服务器广播线程

threading.Thread(target=broadcastMain).start()

# 通知客户端开始接收广播

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

IP = socket.gethostbyname(socket.gethostname())

IP = IP[:IP.rindex('.')]+'.255'

sock.sendto(b'startBroadCast', (IP, 10000))

buttonStopBroadCast['state'] = 'normal'

buttonStartBroadCast['state'] = 'disabled'

buttonStartBroadCast = tkinter.Button(root, text='开始屏幕广播', command=onbuttonStartBroadCastClick)

buttonStartBroadCast.place(x=20, y=380, width=100, height=30)

def onbuttonStopBroadCastClick():

global broadcasting

broadcasting = False

sockBroadCast.close()

buttonStopBroadCast['state'] = 'disabled'

buttonStartBroadCast['state'] = 'normal'

buttonStopBroadCast = tkinter.Button(root, text='结束屏幕广播', command=onbuttonStopBroadCastClick)

buttonStopBroadCast['state'] = 'disabled'

buttonStopBroadCast.place(x=130, y=380, width=100, height=30)

3、学生端收到教师端通过UDP广播发送的屏幕广播指令之后,创建TCP Socket,连接教师端,并接收教师端发来的屏幕截图,然后使用创建顶端显示的tkinter界面用来显示屏幕截图。主要功能代码如下:

# 使用TCP接收广播

def receiveBroadCast():

# 获取屏幕尺寸,创建顶端显示的无标题栏窗体

screenWidth = 640

screenHeight = 480

top = tkinter.Toplevel(root,

width=screenWidth,

height=screenHeight)

top.overrideredirect(True)

# 顶端显示

top.attributes('-topmost', 1)

# 创建画布,用来显示图像

canvas = tkinter.Canvas(top,

bg='white',

width=screenWidth,

height=screenHeight)

canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverIP = entryServerIP.get()

# 连接服务器10001端口,失败直接返回

try:

sock.connect((serverIP, 10001))

except:

print('error')

top.destroy()

return

# 接收服务器指令

# *****表示开始传输一个新的截图

# #####表示本次广播结束

while True:

data = sock.recv(5)

if data == b'*****':

# 接收服务器发来的一屏图像

# 图像大小,字节总数量

len_head = struct.calcsize('I32sI')

data = sock.recv(len_head)

length, size, sizeLength = struct.unpack('I32sI', data)

length = int(length)

size = eval(size[:int(sizeLength)])

rest = length

image = []

while True:

if rest == 0:

break

elif rest > 40960:

temp = sock.recv(40960)

rest -= len(temp)

image.append(temp)

else:

temp = sock.recv(rest)

rest -= len(temp)

image.append(temp)

image = b''.join(image)

# 更新显示

image = Image.frombytes('RGB', size, image)

image = image.resize((screenWidth, screenHeight))

image = ImageTk.PhotoImage(image)

try:

canvas.delete(imageId)

except:

pass

imageId = canvas.create_image(screenWidth//2, screenHeight//2, image=image)

elif data == b'#####':

# 广播结束

break

# 本次广播结束,关闭窗口

sock.close()

top.destroy()

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python小屋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
SpringBoot自定义注解实现Token校验
来自:blog.csdn.net/qq_33556185/article/details/105420205
良月柒
2021/03/09
5340
HandlerMethodArgumentResolver(三):基于HttpMessageConverter消息转换器的参数处理器【享学Spring MVC】
通过 前面两篇文章 的介绍,相信你对HandlerMethodArgumentResolver了解已经很深刻了。但是你或许和我一样还有一种感觉,似乎还缺点什么: 我们使用非常频繁的@RequestBody是怎么封装请求体的呢???这块使用非常广泛的地方却还木有讲解到,因为它的处理方式和前面的不太一样,因此单摘出来到本文进行详细描述。
YourBatman
2019/09/03
1.5K0
HandlerMethodArgumentResolver(三):基于HttpMessageConverter消息转换器的参数处理器【享学Spring MVC】
SpringMvc源码之解析参数HandlerMethodArgumentResolver
HandlerMethodArgumentResolver是什么?它是springmvc提供的入参解析器,像平常应用的注解@RequestParam @PathVariable @ModelAttribute ...等等修饰在@RequestMapping下的参数上都可以用HandlerMethodArgumentResolver来解析。
简单的程序员
2020/04/18
9430
HandlerMethodArgumentResolver(二):Map参数类型和固定参数类型【享学Spring MVC】
上文 介绍了Spring MVC用于处理入参的处理器:HandlerMethodReturnValueHandler它的作用,以及介绍了最为常用的两个参数处理器子类:PathVariableMethodArgumentResolver和RequestParamMethodArgumentResolver。由于该体系的重要以及庞大,本文将接着继续讲解~
YourBatman
2019/09/03
1.7K0
HandlerMethodArgumentResolver(二):Map参数类型和固定参数类型【享学Spring MVC】
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---一篇文章带你读懂返回值处理器HandlerMethodReturnValueHandler
Spring MVC处理入参靠的是HandlerMethodArgumentResolver这个接口,解析返回值靠的是HandlerMethodReturnValueHandler这个策略接口。
YourBatman
2019/09/03
1.4K0
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---一篇文章带你读懂返回值处理器HandlerMethodReturnValueHandler
springboot源码解析之Model和Map参数解析
通过输出可以看到,这里传入的Model对象和Map对象都是BindingAwareModelMap类型,并且指向同一个对象,BindingAwareModelMap既是Model也是Map
九转成圣
2024/04/10
1570
springboot源码解析之Model和Map参数解析
记一次springboot项目自定义HandlerMethodArgumentResolver不生效原因与解法
本文素材的来源自业务部门技术负责人一次代码走查引发的故事,技术负责人在某次走查成员的代码时,发现他们的业务控制层大量充斥着如下的代码
lyb-geek
2022/10/25
1.1K0
记一次springboot项目自定义HandlerMethodArgumentResolver不生效原因与解法
Spring MVC请求处理过程。你这样回答保证通过面试!
SpringMVC请求处理相信大家都很熟悉了,本篇主要是基于SpringMVC处理请求的流程来阅读并调试源码,以及解决几个仅靠流程图无法解释的问题。
程序员白楠楠
2020/12/07
7430
教你如何通过 ArgumentResolver 与 Filter 优化你的 SpringMVC 设计
Spring 提供了一个非常强大的工具来让你能够为若干 controller 封装通用参数的实例化逻辑,这样,你的 controller 就无需去做那些重复的参数实例化工作,从而让你的 controller 变得更为简洁。这个机制就是本文要介绍的 MethodArgumentResolver。
用户3147702
2022/06/27
4850
HandlerMethodArgumentResolver :深入spring mvc参数解析机制
HandlerMethodArgumentResolver 是 Spring MVC 框架中的一个关键组件,用于解析控制器(Controller)方法的参数。在 Spring MVC 中,当一个请求到达时,DispatcherServlet 会负责找到对应的处理器(即控制器中的方法)来处理这个请求。在处理之前,需要解析方法的参数,这就是 HandlerMethodArgumentResolver 的作用
公众号:码到三十五
2024/07/15
8580
HandlerMethodArgumentResolver :深入spring mvc参数解析机制
你真的了解Spring MVC处理请求流程吗?
前言 阅读本文章大概需要8分钟左右。相信会让你对Spring MVC的理解更加深刻,更上一层楼。 SpringMVC图解 粒度很粗的图解 自己画的.png
用户2032165
2018/07/02
2K0
spring 之 spring-mvc
spring-mvc的核心便是DispatcherServlet,所以初始化也是围绕其展开的。类图:
MickyInvQ
2021/10/22
1.1K0
spring 之 spring-mvc
万字长文,深度解析SpringMVC 源码,让你醍醐灌顶!!
本文将通过阅读源码的方式带大家了解 springmvc 处理请求的完整流程,干货满满。
路人甲Java
2021/10/08
2.4K0
参数解析-HandlerMethodArgumentResolver
今天在做项目时遇到了一个有关参数解析 HandlerMethodArgumentResolver 的使用疑惑。因此去 百度学习了一下,现在记录一下。
Blue_007
2023/11/03
2810
参数解析-HandlerMethodArgumentResolver
第三十六章:基于SpringBoot架构重写SpringMVC请求参数装载
在国内企业开发项目中大多数都已经偏向Spring家族式的开发风格,在前几年国内项目都是以Structs2作为Web开发的主导,不过由于近几年发生的事情确实让开发者对它失去了以往的信心。与此同时Spring家族发布了SpringMVC,而且完美的整合Spring来开发企业级大型Web项目。它有着比Structs2更强大的技术支持以及更灵活的自定义配置,接下来我们就看看本章的内容,我们自定义实现SpringMVC参数绑定规则,根据业务定制参数装载实现方式。 本章目标 根据项目定制SpringMVC参数状态并了解
恒宇少年
2018/06/27
1.4K0
spring mvc之HandlerMethodArgumentResolver
因为:1.加重了我们对请求传过来来的值的取值代码,会使控制器中request.getParamater()之类的代码越来越多;2.不利于测试;3.request.getParamater()只能获取string,如果是Long等其他类型的参数还需要强转,使用起来非常不方便。
BUG弄潮儿
2022/06/30
2710
SpringBoot2核心技术-web开发
ServletModelAttributeMethodProcessor 这个参数处理器支持
yuanshuai
2022/08/22
7800
SpringBoot2核心技术-web开发
如何妙用Spring 数据绑定机制
在剖析完 Spring Boot 返回统一数据格式是怎样实现的?文章之后,一直觉得有必要说明一下 Spring's Data Binding Mechanism 「Spring 数据绑定机制」。
用户4172423
2019/12/25
1.2K0
如何妙用Spring 数据绑定机制
Spring自定义参数解析器设计
我们在开发Controller接口时经常会用到此类参数注解,那这些注解的作用是什么?我们真的了解吗?
程序猿川子
2023/05/04
6470
面试题之--SpringMVC 原理
一次为了解决跨域问题,采用了CORS方法。根据官方解释,只需要在响应头里设置 1、Access-Control-Allow-Origin 2、Access-Control-Allow-Methods 3、Access-Control-Allow-Headers 三个值就可以了,于是想到在HandlerInterceptor#preHandle()里去拦截跨域请求(options),然后再根据自定义注解判断请求的controller是否支持跨域请求,再设置对应的响应头。(项目基于spring3.2.x)但是发现请求死活无法进入preHandle里(项目里只有一个自定义的preHandle,不存在提前被别的HandlerInterceptor返回的情况)。于是利用debug大法,发现spring获取拦截器时是根据url和请求类型进行判断的,由于跨域请类型是options,无法获取对于的handler和HandlerInterceptor,导致直接就返回了,没有进入拦截器里。(spring4.x后有个默认的handler支持处理options)。于是把debug过程中学习到的知识,下次排查问题可以更快。
公众号 云舒编程
2024/01/25
1320
面试题之--SpringMVC 原理
推荐阅读
相关推荐
SpringBoot自定义注解实现Token校验
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档