小项目2
# _*_ coding: utf-8 _*_
__author__ = 'pythonwu'
__date__ = "2018/7/23 16:41"
from tkinter import *
from tkinter.filedialog import askdirectory
import zipfile
import os
from datetime import datetime
import getpass
import logging
from tkinter import messagebox
user = getpass.getuser()
tk=Tk()
tk.title("小工具")
var=IntVar()
path1 = StringVar()
default = StringVar()
services_path = '/data/dfs/tcsoft/dfs/上传目录'
default.set('请输入创建的文件夹名称')
username = StringVar()
username.set('请确认用户:'+user)
def OpenFile():
path_ = askdirectory()
path1.set(path_)
def client_exit():
exit()
def Setfile():
path2=path1.get()
startdir = path2
print(path2)
file_news = datetime.now().strftime("%Y-%m-%d_%H_%M_%S")+'.zip' # 压缩后文件夹的名字
z = zipfile.ZipFile(file_news,'w',zipfile.ZIP_DEFLATED) #参数一:文件夹名
for dirpath, dirnames, filenames in os.walk(startdir):
fpath = dirpath.replace(startdir,'') #这一句很重要,不replace的话,就从根目录开始复制
fpath = fpath and fpath + os.sep or ''#这句话理解我也点郁闷,实现当前文件夹以及包含的所有文件的压缩
for filename in filenames:
try:
z.write(os.path.join(dirpath, filename),fpath+filename)
print ('压缩成功')
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', \
datefmt='%a, %d %b %Y %H:%M:%S',filename="success.log",filemode='a')
logging.debug("User %s is loging %s" % (user,'success'))
except Exception as e:
print('e')
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', \
datefmt='%a, %d %b %Y %H:%M:%S',filename="exception.log",filemode='a')
logging.debug("User %s is loging %s" % (user,repr(e)))
z.close()
def click():
if button1.config('text')[-1] == '上传文件':
messagebox1 = messagebox.askquestion(title='确认界面',message='您确定要上传么')
if messagebox1 == 'yes':
print('确认')
button1.configure(text='已点击')
else :
print('取消')
button1.configure(text='上传文件')
else:
messagebox.showinfo(message='请勿重复点击!')
def lookup():
tk2 = Tk()
tk2.title("服务器文件")
menubar = Menu(tk)
filemenu = Menu(menubar)
menubar.add_command(label='选择文件', command= OpenFile)
menubar.add_command(label='压缩文件', command= Setfile)
menubar.add_command(label='退出', command= client_exit)
tk['menu'] = menubar
#标签控件,显示文本和位图,展示在第一行
Label(tk,text="上传者").grid(row=0,sticky=E)#靠右
Label(tk,text="本地目录").grid(row=1,sticky=W)#第二行,靠左
Label(tk,text="目标目录").grid(row=2,sticky=W)
#输入控件
Entry(tk,textvariable = username).grid(row=0,column=1,padx=10,pady=10)
Entry(tk,textvariable = path1).grid(row=1,column=1)
Entry(tk,textvariable = default).grid(row=2,column=1)
#多选框插件
button=Checkbutton(tk,text="请谨慎使用",variable=var)
button.grid(row=3,columnspan=2,sticky=W)
#插入图片
photo=PhotoImage(file="python.png")
label=Label(image=photo)
label.grid(row=0,column=2,rowspan=2,columnspan=2,
sticky=W+E+N+S, padx=5, pady=5)#合并两行,两列,居中,四周外延5个长度
#按钮控件
button1=Button(tk,text="上传文件",command = click)
button1.grid(row=3,column=2,sticky=E)
button2=Button(tk,text="查看服务器",command = lookup)
button2.grid(row=3,column=3,sticky=E)
#主事件循环
mainloop()
布局:
程序写完了,时间比较赶,两天客户端和服务器端都结束了,服务器端自动识别操作,具体是实现一个观察者去监控这个文件夹,进行写数据库,删除数据库操作,如果你们服务器端使用了watchdog 模块,请注意:当你上传的文件不断变大的时候,这个时候是重复写入数据库的,需要加上判断操作,切记
具体的程序,等我有时间再上传吧
老大给了两个方向:深入研究pyqt业务监控记录(较简单),另一个远程软件编写(看了下c++或者c编写,what‘s the fuck !,买书学习中,ps:书还没到。哈哈哈,到了,就没时间扯淡了),业务的痛点:编写远程控制软件,周六日查了一些资料 :mirror drive vnc的实现方式,但是这个地方有个痛点,根据网上网友的反馈,如果是在window 8 以上的系统版本中,会得到的大量的null值(具体猜测:windows的mirror driver是对本地显卡的镜像,画到显卡的东西都会画到它上面去,我们一般通过filemapping的方式在应用层活动这个驱动里面的图像,已经在前一个时间间隙所变化的区域信息,
win8提供了一种Desktop Duplication的机制,我测试了,跟用MD的方式差不多。
想了很久,我似乎明白了这里面的原因:win8之前,系统的输出合成是用GDI来实现的,画面在系统内存中,而MD的buffer也在系统中,所以系统更新MD也很快;但是到了win8,系统的显示部分严重依赖于GPU,那么系统更新MD只能是等GPU运算完了之后在传输回来,这个一直都是性能的断脚(微软反复警告不要这样做),所以MD的性能在win8后就差了很多了。)
)
--网友的猜测
2.GDI +算法(算法是程序的灵魂,这里就是算法的具体应用,苦恼本人不懂什高深的算法,一些基础知识也都忘的差不多了,多嘴一句,周六日在看python的贝叶斯算法,里面的正太分布(好像也叫高斯分布吧,高中的知识据说,还特地去查了一下,然后脑袋当时就懵了),生活中的大多数都符合正态分布,主要运用于医学和生产实践中)
e
1.分块屏或者异传
前后保存两次的bmp位图,屏幕分成若干块并且编号,前后两个图片对应编号进行像素点比对xor操作,将不相等则压缩发送
2.固定行隔行扫描,动态分块隔行扫描
固定块隔行扫描:是保存两次bmp图像,把屏幕分成若干块编号,然后扫描,不通的是扫描方法是隔若干行扫描一行,主要应用于电视信号的发送与接收中。它的特点是把每秒传送25幅(帧)画面用每秒传送50次的方法来消除闪烁感,即一面传送两次,第一次扫描奇数行,第二次扫描偶数行,因而称为隔行扫描
在固定块隔行扫描的基础上,改“把屏幕分成若干块”为“由屏幕的变化区域动态确定要发送的矩形”。当扫描到有不相同的行时,由一个恒定的值确定变化矩形的宽,然后在这个宽度范围内向左和向右对比像素点,确定变化矩形的长,再把矩形的坐标点和矩形的图像(byte[]数组)保存到发送队列,接着由之前 扫描行的编号+矩形的宽度所得的行编号开始扫描,重复上面的操作,扫描到屏幕的最后一行为止,最后服务端传输发送队列的数据到客户端。客户端按矩形的坐标和数据,把矩形paint到picture控件上
在动态隔行扫描算法的基础上,又发展起来“热点追踪”的思想,即跟踪鼠标的操作,因为这是最容易引起变化的地方,因为鼠标的移动,鼠标的点击,屏幕都会变化
3.RDP实现:直接pass
使用图形驱动技术:(摘录)
(2) API Hook技术在实际截屏时,采用API函数实现,截取DDB位图,必须经过一次DDB到DIB的转换;而驱动技术直接从其管理的DIB位图(表面)中将截取区域的图形数据拷贝到应用程序,显著的降低了一次截屏的时间消耗
计算机屏幕图像的截取在屏幕的录制、计算机远程控制以及多媒体教学软件中都是关键术,基于Windows操作系统有多种截屏方法,研究的重点集中在如何快速有效的截取DBI(Device-Independent Bitmap)格式的屏幕图形数据现在商业软件流行的截屏技术主要采取的Api Hook技术,但这种技术一次截屏仍有较大的时间消耗,这样就对运行软件的硬件仍有较多的限制,而且是一种非标准的技术,不为微软公司所推荐
1截屏技术
1.1使用api hook技术
使用api hook技术截屏基于一下的原理;多数屏幕图形的绘制都是通过调用用户态gdi32.dll中的绘图函数实现的,如果利用api hook技术拦截系统中所有对这些函数的调用,就可以得到屏幕图形刷新或变化的区域坐标;然后使用api函数bitblt将刷新或者变化后的屏幕区域的ddb格式的位图拷贝到内存中,接着使用函数getbits将ddb位图转换为dbi位图,最后压缩、存储或者传输
这种方案只有捕捉到变化,才进行截屏这样每次截屏都是有效的操作每次(第一次除外)仅截取了栓新或变化部分,从根本上解决了数据量大的问题但是这种技术仍然有一下缺点:1实际截屏采用的api函数,截取的是ddb位图,要经过一次格式转换,耗时较大2如果屏幕变化区域矩形的坐标r1、r2、……rn相继到达,为了不是屏幕变化的信息丢失,通常不是逐个截取,而是将矩形坐标合并,这样就可以截取并未变化的区域,不经增加截屏的时间消耗,而且产生冗余数据3该技术不支持directdraw技术,由于应用程序可能使用directdraw驱动程序进行直接操纵显示内存、硬件位块转移,硬件重叠和交换表面等图形操作,而不必进行gdi调用,所以此时api hook技术将失去效用,不能捕捉屏幕变化4api hook技术在屏幕取词,远程控制和多媒体教学中都有实际的应用,但是这种技术是一种非标准的技术,微软公司并不推荐使用
directdraw 技术解释看这个 https://blog.csdn.net/frankiewang008/article/details/39893329,主要就是游戏运用了硬件加速,直接控制计算机硬件设备不经过gdi程序,哎。。。。
1.2 使用图形驱动技术
该技术的原理:应用程序调用win32 gdi 函数进行图形输出请求,这个请求通过核心模式gdi发送核心模式gdi把这些请求发送到相应的图形驱动程序如,显示器驱动程序,通信流如图现将该技术详细解释如下:
(1)显示器驱动输出一系列设备驱动程序接口DDI(Device Driver Interface)函数供GDI调用信息通过这些入口点的输入/输出参数在GDI和驱动程序之间传递
(2) 在显示器驱动加载时,GDI调用显示器驱动程序函数DrvEnableDriver,在这里我们向GDI提供显示器驱动支持的,可供GDI调用的DDI函数入口点,其中部分时将要Hook的图形输出函数
(3) 在GDI调用函数DrvEnableDriver成功返回后,GDI调用显示器驱动的DrvEnablePDEV函数,在这里可以设置显示器的显示模式,然后创建一个PDEV结构,PDEV结构是物理显示器的逻辑表示
(4) 在成功创建PDEV结构之后,显示驱动为视频硬件创建一个表面,该表面可以是标准的DIB位图管理表面,然后驱动程序使该表面与一个PDEV结构相关联,这样显示驱动支持的所有绘画操作都将在该DIB位图表面上进行
(5) 当应用程序调用用户态GDI32.DLL中的绘图函数发出图形请求时,该请求将图形引擎通过相应的DDI函数发送到显示驱动,显示驱动程序将这次图形变化事件通知应用程序
(6) 应用程序接受到通知后,调用函数ExtEscape发出一个请求,并通过参数传递一个缓冲区Buffer,图形引擎调用DDI函数DrvEscape处理应用层的ExtEscape调用,将变化部分的图形数据从其创建的表面拷贝Buffer,这样数据就从核心层图形驱动传到应用层
(7) 应用程序接收到的图形数据已是DIB标准格式,所以可以直接进行压缩传输或储存
1.3图形驱动技术的特点
上面叙述了采用图形驱动实现屏幕实现截屏的原理和过程,可以看出这种技术涉及核心图形驱动的编写,实现上较为复杂,而其具备的优点主要为:
(1) 驱动技术只截取变化的屏幕区域,这一点与API Hook技术相当;但驱动技术是一种标注技术,为微软公司所推荐
(3) 如果屏幕图形小区域范围变化较快,屏幕变化区域矩形坐标R1、R2、R3……、Rn相继到达,由于一次截屏时间消耗降低,区域矩形坐标叠加的概率变小,这样屏幕变化区域及时的得到了处理,不仅增加了连续性,而且截屏时间消耗和产生的数据量一般不会出现峰值,这也是这种技术的优越之处
经过以上对比,无论是做远程桌面还是屏幕录制,基于MirrorDriver的屏幕截取将会是一个不错的选择,无论从性能占用资源的大小(主要是cpu),取得的数据量来说都要优于Hook
所以两个办法:1.MD和DD进行联合开发
driver内部实现的原理大致就是把显示输出拷贝到一个缓冲区当中,并且记录每次屏幕更新的矩形区域根据这些输出,应用程序就很容易得到缓冲区中的数据了