视频监控笔记(五):Jetson Nano上通过Tkinter和Socket实现GUI文件传输

简介: 这篇文章介绍了如何使用Python的Tkinter和Socket在Jetson Nano上实现图形用户界面(GUI)的文件传输系统,包括服务器端和客户端,能够进行文件的发送和接收,并展示传输进度。

图片

bj.png
bj.png

服务器端

Server.py

# coding=utf-8

import cv2
import os
import json
import socket
import threading
#读取文件的最大数
max_len=1024
import tkinter.messagebox

def socket_server():
    # 端口号和IP地址
    remote_addr = ("192.168.80.129", 9999)

    # 绑定IP地址和端口号PORT
    socket_Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_Server.bind(remote_addr)

    # 监听
    socket_Server.listen()
    print('正在监听来自客户端的消息......')
    return socket_Server

def Server_Recv_File():
    """
    :param socket: 服务端套接字
    :param root: 主窗口
    :return:
    """
    socket_Server=socket_server()
    new_socket, addr = socket_Server.accept()
    #获取客户端发送的消息头
    msg_header=new_socket.recv(max_len)
    header=json.loads(msg_header.decode('utf-8'))
    #输出客户端发送的消息头信息
    print(header)
    #保存接收文件的地方
    curr_path=os.getcwd()
    filename=curr_path+'/server_recv_File/server_recv_'+header['filename']+header['msg_type']
    get_file_Size=header['msg_len']
    file_size=0
    #输出文件名和文件大小
    print('文件名: {}'.format(filename))
    print('file_size: {}'.format(get_file_Size))
    recv_count=0
    #如果文件不存在则创建
    if os.path.exists(filename)==False:
        with open(filename,'wb') as fp:
            while file_size!=get_file_Size:
                message=new_socket.recv(max_len)
                fp.write(message)
                file_size+=len(message)
                recv_count+=1
    else:
        with open(filename,'wb') as fp:
            while file_size!=get_file_Size:
                message=new_socket.recv(max_len)
                fp.write(message)
                file_size+=len(message)
                recv_count+=1
    print('接收次数: {}'.format(recv_count))
    new_socket.close()
    print('发送完成...')

#服务端接收客户端的下载文件请求,并进行发送
def server_Send_File():
    """
    :param new_socket:
    :return:
    """
    socket_Server = socket_server()
    new_socket, addr = socket_Server.accept()
    filepath=new_socket.recv(max_len).decode('utf-8')
    print('filepath: {}'.format(filepath))
    # 分离路径和文件名
    path, filename = os.path.split(filepath)
    print('path: {}'.format(path))
    print('filename: {}'.format(filename))
    # 分离文件名和文件后缀
    file, class_file = os.path.splitext(filename)
    # 首先将消息头发送至服务端
    # 获取文件大小
    # file_size=os.path.getsize(filename)
    file_Size = os.stat(filepath).st_size
    msg_header = {'filename': file, 'msg_type': class_file, 'msg_len': file_Size}
    msg_header_bytes = bytes(json.dumps(msg_header), encoding='utf-8')
    # 当消息头的长度不满1024时,使用空格填充
    msg_header_bytes += b'' * (max_len - len(msg_header_bytes))
    new_socket.send(msg_header_bytes)
    file_len = 0
    recv_count = 0
    # 发送的文件头大小
    print('msg_header_bytes: {}'.format(len(msg_header_bytes)))
    # 发送的文件大小
    print('file_size: {}'.format(file_Size))
    with open(filepath, 'rb') as fp:
        while file_len != file_Size:
            message = fp.read(max_len)
            new_socket.send(message)
            file_len += len(message)
            recv_count += 1
    print('发送次数: {}'.format(recv_count))

    new_socket.close()
    print('发送完成...')

if __name__=='__main__':
    print('Pycharm')
    Server_Recv_File()

客户端

clinet.py

import os
import tkinter

import cv2
import json
import socket
import threading
from tkinter import ttk
#读取文件的最大数
max_len=1024

def socket_client():
    #端口号和IP地址
    remote_PORT=5555
    remote_IP=socket.gethostbyname(socket.gethostname())
    remote_addr=(remote_IP,remote_PORT)

    #绑定端口号和IP地址
    socket_Client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    socket_Client.connect(remote_addr)
    return socket_Client

def ProgressBar(root,text):
    label=tkinter.Label(root,text=text,font=('黑体',14))
    label.place(x=100,y=500)
    progressbar=ttk.Progressbar(root)
    progressbar.place(x=200,y=500)
    #设置进度条的最大值
    progressbar['maximum']=100
    #设置进度条的长度
    progressbar['length']=280
    #初始化初值
    progressbar['value']=0

    return progressbar

def Client_Send_File(socket_Client,filepath,root):
    """
    :param socket: 客户端套接字
    :param filename: 要传输的文件
    :param root:主窗口
    :return:
    """
    progressbar=ProgressBar(root,'发送进度')
    #分离路径和文件名
    path, filename = os.path.split(filepath)
    print('path: {}'.format(path))
    print('filename: {}'.format(filename))
    #分离文件名和文件后缀
    file, class_file = os.path.splitext(filename)
    #首先将消息头发送至服务端
    #获取文件大小
    # file_size=os.path.getsize(filename)
    file_Size=os.stat(filepath).st_size
    msg_header={'filename':file,'msg_type':class_file,'msg_len':file_Size}
    msg_header_bytes=bytes(json.dumps(msg_header),encoding='utf-8')
    #当消息头的长度不满1024时,使用空格填充
    msg_header_bytes+=b''*(max_len-len(msg_header_bytes))
    socket_Client.send(msg_header_bytes)
    file_len=0
    recv_count=0
    #发送的文件头大小
    print('msg_header_bytes: {}'.format(len(msg_header_bytes)))
    #发送的文件大小
    print('file_size: {}'.format(file_Size))
    with open(filepath,'rb') as fp:
        while file_len!=file_Size:
            message=fp.read(max_len)
            socket_Client.send(message)
            file_len+=len(message)
            progressbar['value']=file_len/file_Size*100
            recv_count+=1
    print('发送次数: {}'.format(recv_count))

    socket_Client.close()
    print('发送完成...')

#客户端从服务端下载文件
def Download_Server(socket_Client,filepath,root):
    """
    :param socket_Client: 客户端套接字
    :param filepath: 文件路径
    :param root: 主窗口
    :return:
    """
    progressbar=ProgressBar(root,'下载进度')
    socket_Client.send(filepath.encode('utf-8'))
    # 获取客户端发送的消息头
    msg_header = socket_Client.recv(max_len)
    header = json.loads(msg_header.decode('utf-8'))
    # 输出客户端发送的消息头信息
    print(header)
    # 保存接收文件的地方
    curr_path = os.getcwd()
    filename = curr_path + '\\client_recv_File\\client_recv_' + header['filename'] + header['msg_type']
    get_file_Size = header['msg_len']
    file_size = 0
    # 输出文件名和文件大小
    print('文件名: {}'.format(filename))
    print('file_size: {}'.format(get_file_Size))
    recv_count = 0
    # 如果文件不存在则创建
    if os.path.exists(filename) == False:
        with open(filename, 'wb') as fp:
            while file_size != get_file_Size:
                message = socket_Client.recv(max_len)
                fp.write(message)
                file_size += len(message)
                progressbar['value']=file_size/get_file_Size*100
                recv_count += 1
    else:
        with open(filename, 'wb') as fp:
            while file_size != get_file_Size:
                message = socket_Client.recv(max_len)
                fp.write(message)
                file_size += len(message)
                progressbar['value'] = file_size / get_file_Size * 100
                recv_count += 1
    print('接收次数: {}'.format(recv_count))
    socket_Client.close()
    print('下载完成...')

if __name__=='__main__':
    print('Pycharm')
    socket_Client=socket_client()
    Client_Send_File(socket_Client,'File\\2014.rar')

总代码


import os,cv2,socket,tkinter,threading
import Client
import Server
from tkinter import ttk
from PIL import Image,ImageTk
from tkinter import filedialog
from tkinter.messagebox import showerror,showinfo,showwarning

root=tkinter.Tk()
#设置主窗口标题
root.title('远程更新——Keep_Trying_Go')
#设置主窗口大小
root['width']=900
root['height']=500
#固定窗口大小
root.resizable(0,0)
#设置主窗口背景颜色
root['background']='#FFFFFF'
#设置主窗口图标
#设置标题为图像形式,第一个参数设置为True,表示该图标适用于所有的窗口
#这里注意图像格式为.png,就算是从.jpg到.png的格式转换也不能,只能是.png格式
root.iconphoto(True,tkinter.PhotoImage(file='2.png'))

#背景图自适应大小
def ChangeBackground(w,h,w_box,h_box,PIL_Image):
    """
    :param w: 图片的宽度
    :param h: 图片的高度
    :param w_box: 画布的宽度
    :param h_box: 画布的高度
    :param PIL_Image:
    :return:
    """
    factor_w=1.0*w_box/w
    factor_h=1.0*h_box/h
    factor=min([factor_h,factor_w])
    #新的图片高度和宽度
    width=int(w*factor)
    height=int(h*factor)
    print('width: {}'.format(width))
    print('height: {}'.format(height))
    return PIL_Image.resize((width,height),Image.Resampling.LANCZOS)

tk_image_file=''
def setBackground(root,filename):
    """
    :param root: 主窗口
    :return:
    """
    global tk_image_file
    PIL_Image=Image.open(filename)
    w,h=PIL_Image.size
    PIL_Image_Size=ChangeBackground(w,h,600,450,PIL_Image)
    # PIL.ImageShow.show(PIL_Image_Size)
    try:
        #方式一
        #创建画布
        canvas=tkinter.Canvas(root,bg='white',width=598,height=450,borderwidth=1)
        canvas.place(x=5,y=0)
        #加在图片文件
        tk_image_file=ImageTk.PhotoImage(PIL_Image_Size)
        #将图片放置在创建的画布上
        image=canvas.create_image(0,0,anchor='nw',image=tk_image_file)
        # #将图像放置画布上端,也就是主窗口‘前方’
        # canvas.pack(side='top')
        #方法二
        # label=tkinter.Label(root,image=tk_image_file,width=600,height=450)
        # label.place(x=90,y=0)
    except :
        print('加载图像出错')

def SelectBackground(root):
    """
    :param root:
    :return:
    """
    filename=filedialog.askopenfilename(title='选择传输文件')
    if not filename:
        showinfo(title='提示',message='未选择传输文件')
        # 如果没有选择采用默认
        filename='2.png'
    setBackground(root,filename)
btn_cov=tkinter.Button(root,text='修改背景',font=('newspaper',14),width=17,height=1,cursor='hand2',command=lambda :SelectBackground(root),bg='#00FF7F')
btn_cov.place(x=615,y=300) # 350

def CloseEvent(root):
    """
    :param root:
    :return:
    """
    btn_close=tkinter.Button(root,text='退出',font=('newspaper',14),width=17,height=1,cursor='hand2',command=root.destroy,background='#708090')
    btn_close.place(x=615,y=400)

def SelectFile(root):
    """
    :param root:
    :return:
    """
    filename=filedialog.askopenfilename(title='选择传输文件')
    if not filename:
        showinfo(title='提示',message='请选择发送文件')
        # 如果没有选择采用默认
        filename='main.py'
    socket_Client=Client.socket_client()
    threading_client=threading.Thread(target=Client.Client_Send_File,args=(socket_Client,filename,root))
    threading_client.start()

btn_client=tkinter.Button(root,text='选择发送文件',font=('newspaper',14),width=17,height=1,cursor='hand2',bg='#00FF7F',command=lambda :SelectFile(root))
btn_client.place(x=615,y=90)

def SwitchServer(root):
    """
    :param root:
    :return:
    """
    threading_server=threading.Thread(target=Server.Server_Recv_File)
    threading_server.start()

btn_client=tkinter.Button(root,text='开启接收文件服务端',font=('newspaper',14),width=17,height=1,cursor='hand2',bg='#00FF7F',command=lambda :SwitchServer(root))
btn_client.place(x=615,y=200) # 140

def SelectdownloadFile(root):
    filename=filedialog.askopenfilename(title='选择下载文件')
    if not filename:
        showinfo(title='提示',message='请选择您要下载的文件')
        #如果没有选择采用默认
        filename='main.py'
    socket_Client=Client.socket_client()
    threading_client=threading.Thread(target=Client.Download_Server,args=(socket_Client,filename,root))
    threading_client.start()

# btn_client_down=tkinter.Button(root,text='选择下载文件',font=('newspaper',14),width=17,height=1,cursor='hand2',bg='#00FF7F',command=lambda :SelectdownloadFile(root))
# btn_client_down.place(x=615,y=210)

def SwitchdownloadServer(root):
    """
    :param root:
    :return:
    """
    threading_server=threading.Thread(target=Server.server_Send_File)
    threading_server.start()

# btn_server_send=tkinter.Button(root,text='开启下载文件服务端',font=('newspaper',14),width=17,height=1,cursor='hand2',bg='#00FF7F',command=lambda :SwitchdownloadServer(root))
# btn_server_send.place(x=615,y=260)

if __name__=='__main__':
    print('welcome ...')
    setBackground(root, filename='bj.png')
    CloseEvent(root)
    root.mainloop()
目录
相关文章
|
2天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
3天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
578 22
|
3天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
10天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
578 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2