老师的博客:

server端

import json
import struct
import json
import struct
import socket
import os
sk = socket.socket()
sk.bind(('192.168.43.155',8080))
sk.listen()

conn,addr = sk.accept()
dic_len = conn.recv(4)  # 4个字节 数字的大小
dic_len = struct.unpack('i',dic_len)[0]
content = conn.recv(dic_len).decode('utf-8')  # 70
content_dic = json.loads(content)
if content_dic['operate'] == 'upload':
    with open(content_dic['filename'],'wb') as f:
        while content_dic['filesize']:
            file = conn.recv(1024)
            f.write(file)
            content_dic['filesize'] -= len(file)
elif content_dic['operate'] == 'download':
    file_path=content_dic['path']
    file_name=os.path.basename(file_path)
    file_size=os.path.getsize(file_path)
    dic_from={'file_size':file_size,'file_name':file_name}
    dic_from=json.dumps(dic_from).encode('utf-8')
    dic_lenth=struct.pack('i',len(dic_from))
    print(dic_lenth,type(dic_lenth))
    conn.send(dic_lenth + dic_from)
    with open(file_path,mode='rb') as f:
        while file_size>0:
            ret=f.read(1024)
            conn.send(ret)
            file_size -= 1024
    print('传输完成')
else:
    print('错了')
conn.close()
sk.close()

 

client端

import os
import json
import struct
import socket

sk = socket.socket()
sk.connect(('192.168.43.155',8080))

def get_filename(file_path):
    filename = os.path.basename(file_path)#os.path.basename(path) 返回path最后的文件名。
    # 如果path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
    return filename

#选择 操作
operate = ['upload','download']
for num,opt in enumerate(operate,1):#枚举函数,第一个参数是对象,第二是是下标的开始计数
    print(num,opt)
num = int(input('请输入您要做的操作序号 : '))
if num == 1:
    '''上传操作'''
    file_path = input('请输入要上传的文件路径 : ')
    file_size = os.path.getsize(file_path)  # 获取文件大小
    file_name = get_filename(file_path)#获取文件路径
    dic = {'operate': 'upload', 'filename': file_name,'filesize':file_size}
    str_dic = json.dumps(dic).encode('utf-8')
    ret = struct.pack('i', len(str_dic))  # 将字典的大小转换成一个定长(4)的bytes
    sk.send(ret + str_dic)
    with open(file_path,'rb') as  f:
        while file_size:
            content = f.read(1024)
            sk.send(content)
            file_size -= len(content)
    print('上传成功')
elif num == 2:
    '''下载操作'''
    download_path=input('请输入你要下载的路径')
    dic=json.dumps({'operate':'download','path':download_path}).encode('utf-8')
    download_path_unm=struct.pack('i',len(dic))
    sk.send(download_path_unm+dic)#发送信息
    get_information=sk.recv(4)#接受即将带来的信息的长度
    get_information_real=struct.unpack('i',get_information)[0]#转化为真是数字

    get_real_information=sk.recv(get_information_real).decode('utf-8')#接受,解压

    get_real_information=json.loads(get_real_information)
    download_file_name=get_real_information['file_name']
    download_file_size=get_real_information['file_size']
    with  open(download_file_name,mode='wb') as f:
            while download_file_size>0:
                print(download_file_size)
                code=sk.recv(1024)
                f.write(code)
                download_file_size -= 1024

    print('下载成功')
sk.close()

 

说明:

上传老师写的,我自己是吧下载给补充的写了,所以上传和下载的代码应该还可以优化一下。

下面是在写代码中遇到的问题,总结一下:

1.struct中,把数字转化为4的固定长度的bytes类型,所以就不需要再进行encode操作,因为本身就是bytes类型的,而却其编码方式叫特别,只能通过unpack才能转化为数字,记住是int,通过其他方式。例如。gbk。utf-8decode是str类型,但是内容确实空白的·另外关于unpack得到的是个元祖,所以的到的值需要取第0位数,来取到你需要的数字。

2,json模块,由于json是把数据类型给转化为str类型的,所以还需要在进行encode()的操作,来吧其转化为bytes类型的。所以拿到是,应该首先decode()。

3,send的是时候可以采用(内容1+内容2)的形式,表示两次发送的

4,下载上传是必需要把文件的大小拿到,然后采用相等的大小传输,所以需要把文件大小先传输过去,然后在进行同时的收发操作。

5.while循环是,条件应该写成长度<0是结束,因为有很大的情况下,大小-=1024是不可能刚好减到0的,如果为负数的时候,条件还是为真,所以不会终止循环,然后就出不来了。

6,数据传输和接受的时候都是以bytes的方式打开或者写入的,而且在不需要写编码方式,因为传输的有可能是视频。