该程序基于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()
12-27 19:46
查看更多