该程序基于tcp协议,实现服务端向客户端传输文件的功能。
当服务端发送的文件过大时,客户端无法正常接受,造成黏包现象。解决的方案是,每次发送文件时,告诉客户端服务器要发送文件的大小,同时将文件按指定大小(m)拆分开发送。客户端在接受到文件大小后,按指定大小(n)进行接受。。感兴趣的话可以自己试试看,m和n的之间存在什么关系。
这里用struct模块优化代码。len_a = struct.pack('i', len(a))将a的值长度计算出来,并转化成4位的bytes类型; struct.unpack('i',len)将bytes类型的len转化成int型的数字,并放入到元组中;所有b= struct.unpack('i',len).[0]中,b是变量a的值长度,即len(a)=b。关于struct的使用,详细使用看【】注释对应的行。当然,我们也可以通过其len函数来获取a值长度,然后再转化成bytes类型,再解码。
服务端的代码
1 import json 2 import socket 3 import struct 4 import os 5 server = socket.socket() 6 server.bind(('127.0.0.1',9002)) 7 server.listen() 8 9 conn,addr = server.accept() 10 #发送文件的信息:文件名、文件大小、文件路径 11 f_head = {'f_name': r'xxxx2019.doc', #文件名称(r表示字符串不发生转换) 12 'f_size': None, #文件大小(未赋值) 13 'f_path': r'C:\Users\Apple\Desktop\学习\s1' #文件存储位置 14 } 15 fPath = os.path.join(f_head['f_path'],f_head['f_name']) #文件路径(位置+名字) 16 fSize = os.path.getsize(fPath) #文件大小 17 f_head['f_size'] = fSize #给字典f_head的f_size赋值 18 j_head = json.dumps(f_head) #字典f_head转换成字符串 19 b_head = j_head.encode('utf-8') #字符串(f_head)转bytes 20 head_len = struct.pack('i', len(b_head)) #【获取(f_head)bytes类型长度】 21 conn.send(head_len) #发送f_head长度到客户端 22 conn.send(b_head) #发送f_head内容到客户端 23 num = 1024 #m 24 25 #读取fpath路径下的文件,拆分文件并发送;至所有文件发送完毕跳出循环26 with open(fPath,'rb') as f: 27 while fSize > num: 28 conn.send(f.read(num)) 29 fSize = fSize - num 30 conn.send(f.read(fSize)) 31 32 conn.close() 33 server.close()
客户端的代码
1 import json 2 import socket 3 import struct 4 5 client = socket.socket() 6 client.connect(('127.0.0.1', 9002)) 7 8 num = 1024 #n 9 head_len = struct.unpack('i', client.recv(4))[0] #【接受服务端发来的f_head(bytes类型)的大小,并转化成int类型】 10 j_head = client.recv(head_len).decode('utf-8') #接受服务端发来的f_head,并解码得到字符串 11 head = json.loads(j_head) #讲字符串类型的f_head,转换为字典类型 12 fSize = head['f_size'] #获取head的f_size值(即服务端f_head的f_size值) 13 14 #分部接受来自服务端的文件,并写入;至所有文件接受完毕结束循环。15 with open(head['f_name'],'wb') as f: 16 while fSize > num: 17 msg = client.recv(num) 18 f.write(msg) 19 fSize = fSize - num 20 msg = client.recv(fSize) 21 f.write(msg) 22 23 client.close()