32 实现大文件的传输、切换目录
首先回顾一下小文件的传输
import socket import os import json sk = socket.socket() sk.connect(("127.0.0.1", 8001)) menu = {"1": "upload", "2": "download"} for k, v in menu.items(): print(k, v) num = input("请输入功能选项:") if num == "1": dic = {"opt": menu.get(num), "filename": None, "content": None} file_path = input("请输入一个绝对路径:") filename = os.path.basename(file_path) with open(file_path, "r", encoding="utf-8") as f: content = f.read() dic["filename"] = filename dic["content"] = content str_dic = json.dumps(dic) sk.send(str_dic.encode("utf-8")) elif num == "2": pass
import socket import json sk = socket.socket() sk.bind(("127.0.0.1", 8001)) sk.listen() conn, addr = sk.accept() str_dic = conn.recv(9090).decode("utf-8") dic = json.loads(str_dic) if dic["opt"] == "upload": filename = "1" + dic["filename"] with open(filename, "w", encoding="utf-8") as f: f.write(dic["content"]) elif dic["opt"] == "download": pass conn.close() sk.close()
粘包
tcp协议粘包,udp不粘包
合包机制(nagle算法)-- 发生在发送端
拆包机制-- 发生在发送端 ,由于最大传输单元(Maximum Transmission Unit,MTU)的限制,会把数据拆包进行发送
subprocess.Popen() 执行系统命令
解决粘包
新模块 struct
struct.pack(type,num)
type:是num的类型
num :是一个数字
r = struct.pack(type,num) 把一个数字打包成一个四字节的bytes
struct.unpack(type,r)
功能:解包,把r解成原数字,结果是一个元组,原数字在元组的下标位0的位置
大文件传输:
import socket import os import json sk = socket.socket() sk.connect(("127.0.0.1", 8001)) menu = {"1": "upload", "2": "download"} for k, v in menu.items(): print(k, v) num = input("请输入功能选项:") if num == "1": dic = {"opt": menu.get(num), "filename": None, "filesize": None} file_path = input("请输入一个绝对路径:") # 文件的绝对路径 filename = os.path.basename(file_path) # 文件名字 filesize = os.path.getsize(file_path) # 获取用户输入的路径中文件的大小 dic["filename"] = filename dic["filesize"] = filesize str_dic = json.dumps(dic) sk.send(str_dic.encode("utf-8")) # 将被填充完成的字典先发送给服务器 sk.recv(1024) # 为什么要有一个recv? # 因为上边send字典时,如果程序执行过快,可能会马上执行到下边的send(content) # 此时有可能会发生粘包,所以在此中间加一个recv,为了避免粘包 with open(file_path, "rb") as f: while filesize: content = f.read(1024) sk.send(content) filesize -= len(content) elif num == "2": pass
import socket import json sk = socket.socket() sk.bind(("127.0.0.1", 8001)) sk.listen() conn, addr = sk.accept() str_dic = conn.recv(100).decode("utf-8") conn.send(b'ok') # str_dic = {"opt":menu.get(num),"filename":None,"filesize":None} dic = json.loads(str_dic) if dic["opt"] == "upload": filename = "1" + dic["filename"] with open(filename, "ab") as f: while dic['filesize']: content = conn.recv(1024) f.write(content) dic['filesize'] -= len(content) elif dic["opt"] == "download": pass conn.close() sk.close()
切换目录
import socket import os sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() conn, addr = sk.accept() def send_data(conn, path): '''你给我一个目录,我把目录发给client''' lis_dir = os.listdir(path) str_dir = '--'.join(lis_dir) conn.send(str_dir.encode('utf-8')) abs_path = conn.recv(1024).decode('utf-8') # 获取用户输入的绝对路径 current_dir = abs_path + '/' # 以下再处理,都要根据当前路径去处理,无论是返回上一层,还是进入下一层 send_data(conn, current_dir) # 把用户输入的路径下的所有文件及文件夹返回给客户端 # C:/Program Files (x86)/Common Files while 1: cmd = conn.recv(1024).decode('utf-8') if cmd == '..': current_dir = current_dir.split('/')[:-2] current_dir = '/'.join(current_dir) + '/' # if 如果当前是C盘: # 就返回给客户端告诉说没有上一层了! send_data(conn, current_dir) else: filename = cmd.split(' ')[1] # 获取用户输入的文件名字 current_dir += filename + '/' # 将文件名字添加到当前路径下,组成一个完整的新路径 if os.path.isdir(current_dir): # 如果客户输入的文件名字是一个文件夹 send_data(conn, current_dir) else: # 如果不是一个文件夹 conn.send(b'bu shi wen jian jia') # conn.close() # sk.close()
import socket import os sk = socket.socket() sk.connect(('127.0.0.1', 8080)) abs_path = input('请输入您的根目录:') sk.send(abs_path.encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('--')) while 1: cmd = input('请输入>>>') # cd + 文件夹 .. if cmd == '..': sk.send(cmd.encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('--')) if cmd == 'cd': filename = input('请输入一个文件夹名:') sk.send((cmd + ' ' + filename).encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('--')) sk.close()