python中使用socket编程实现带有界面的客户端向服务端发送文件和下载文件

这是一个基于Python实现的文件传输系统,包括发送文件和下载文件的功能。客户端和服务端通过TCP进行交互,支持文件的选择和传输进度显示。用户可以选择背景图片并有退出操作。在发送文件前需开启服务端,下载文件同样需要开启服务端。系统提供了错误提示,如未选择文件会给出相应提示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一主界面:
在这里插入图片描述
**二:发送文件界面:**首先需要开启发送文件服务端(这里需要注意的是每一次发送文件之前都需要开启一次服务端,因为我在这里将每一次发送文件之后就关闭了客户端和服务端之间的连接)
在这里插入图片描述
输出相关客户端和服务端的文件传输过程中的信息:
在这里插入图片描述
如果发送文件没有选择,将会得到提示“请选择发送文件”
在这里插入图片描述
三:下载文件主界面:首先需要开启下载文件服务端(同样,这里需要注意的是每一次发送文件之前都需要开启一次服务端,因为我在这里将每一次发送文件之后就关闭了客户端和服务端之间的连接)
注意:这里的下载文件的思路:
1.当开启下载服务端之后,客户端选择要下载的文件
2.客户端将要下载的文件路径发送给服务端
3.服务端根据客户端发送来的文件路径,将要发送的文件大小,类型,文件名打包为消息头发送给客户端
4.服务端将根据文件路径打开文件进行分段发送
5.客户端也根据服务端发送的文件消息头新建一个同样类型的文件名,进行写操作
在这里插入图片描述
当未选择要下载的文件时,也会给出提示“请选择您要下载的文件”。
在这里插入图片描述
如果自己对现在的背景不满意,也可以点击修改背景,换为自己喜欢的图片。
最后就是点击退出操作。
在这里插入图片描述

主界面:

import os
import cv2
import Client
import Server
import socket
import tkinter
import threading
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']=800
root['height']=600
#固定窗口大小
root.resizable(0,0)
#设置主窗口背景颜色
root['background']='#FFFFFF'
#设置主窗口图标
#设置标题为图像形式,第一个参数设置为True,表示该图标适用于所有的窗口
#这里注意图像格式为.png,就算是从.jpg到.png的格式转换也不能,只能是.png格式
root.iconphoto(True,tkinter.PhotoImage(file='title.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.ANTIALIAS)


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='Background.png'
    setBackground(root,filename)
btn_cov=tkinter.Button(root,text='修改背景',font=('黑体',14),width=17,height=1,cursor='hand2',command=lambda :SelectBackground(root),bg='#00FF7F')
btn_cov.place(x=615,y=350)

def CloseEvent(root):
    """
    :param root:
    :return:
    """
    btn_close=tkinter.Button(root,text='退出',font=('黑体',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='File/hometown.jpg'
    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=('黑体',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=('黑体',14),width=17,height=1,cursor='hand2',bg='#00FF7F',command=lambda :SwitchServer(root))
btn_client.place(x=615,y=140)

def SelectdownloadFile(root):
    """
    :param root:
    :return:
    """
    filename=filedialog.askopenfilename(title='选择下载文件')
    if not filename:
        showinfo(title='提示',message='请选择您要下载的文件')
        #如果没有选择采用默认
        filename='File/hometown.jpg'
    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=('黑体',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=('黑体',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('PyCharm')
    setBackground(root, filename='Background.png')
    CloseEvent(root)
    root.mainloop()

客户端代码:Client.py
在主界面中导入:import Client

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

服务端代码:Server.py
在主界面中导入:import Server.py

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

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

    # 绑定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()

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值