Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >跨站数据测试

python socket传输大文件的方法

×××××××××××××方法一:

	发送端
1、计算发送文件大小,然后结合文件的其他信息,组成文件头先发送一次。
2、发送文件数据时用sendall(),一次发送所有数据(好像是重复调用了send())
	接收端
1、接收端根据接受文件的大小和recv_size计算要接收数据的次数,
2、然后把每次接收的数据连在一起
3、因为可能不是整除,最后要判断下最后一次具体接收多少字节数据(感觉也可以不用这样,直接接收)

1、计算文件大小

1、os.path.getsize(filepath)
2、os.stat(filepath).st_size

2、socket接收数据的操作的注意事项

因为下面的原因,我们要在接收端接收头文件时做一些处理,用来与数据文件区分

#服务器
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",8000))
server.listen(3)
while True:
    sock,adddr = server.accept()
    data = sock.recv(1024)
    print(data.decode("utf8")+"\n")
    if(data.decode("utf8") == "111"):
        print("dsfaf")
        server.close()
sock.close()
#客户端
import socket 
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8000))
header_data = {
    'file_size': 1000299,
}
client.send(json.dumps(header_data).encode("utf-8"))
client.send("ripo".encode("utf8"))
client.send("fasdf".encode("utf8"))
client.send("oiposfdpakf".encode("utf8"))
client.send("111".encode("utf8"))
client.close()

服务器输出结果

{"file_size": 1000299}ripofasdfoiposfdpakf111

可见虽然客户端是用多个send函数发送的,服务器采用1024大小的缓冲(sock.recv(1024))区,一次把所有数据的都接收了。这样就不能区分出我们先发送的文件头和文件内容了。

解决方案

1、使用send和recv隔离

在发送端第一次发送数据,也就是发送文件头信息的时候,接收端在接收后在给发送端发送一个数据,
然后发送端接收后(不必处理),相当于在发送文件头信息和文件信息之间加了一步,这样接收端就能区
分开了。

2、(推荐):使用struct计算头文件大小

使用struct库
1、首先在发送端和接收端约定一个fmt,也就是头文件的格式。
2、客户端 
	struct.pack(fmt,v1,v2.....)
3、服务器端
(1)struct.calcsize(fmt),可以计算大小,这样就可以在接收端接收指定大小的数据。这个大小对应头
文件数据的大小。
(2)struct.unpack(fmt,v1,v2.....)

第一种方法最终代码:

#服务器端
import socket
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",3008))
server.listen(3)
while True:
    print("start.......")
    sock,adddr = server.accept()
    d = sock.recv(struct.calcsize("l"))
    total_size = struct.unpack("l",d)
    num  = total_size[0]//1024
    data = b''
    for i in range(num):
        data += sock.recv(1024)
    data += sock.recv(total_size[0]%1024)

    with open("11.png","wb") as f:
        f.write(data)
    sock.close()
sock.close()
#客户端
import socket 
import struct
import os
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",3008))
print("connect success....")
filepath = "1.png"
size =  os.stat(filepath).st_size
f= struct.pack("l",os.stat(filepath).st_size)
client.send(f)
img = open(filepath,"rb")
client.sendall(img.read())
img.close()
client.close()

××××××××××××方法二(推荐):

方法二:
	发送端(事先知道接收的缓冲区大小buf)
1、读取要发送的文件,获取总大小
2、每次发送buf大小的数据,是的接收端正好接这么多
3、一直发,直到把文件的数据发送完
	接收端
1、一直接收直到数据的不大于0

第二种方法最终代码:

#服务器
import socket
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",3008))
server.listen(3)
while True:
    print("start......")
    sock,adddr = server.accept()
    total_data = b''
    num = 0
    data = sock.recv(1024)
    total_data += data
    num =len(data)
    # 如果没有数据了,读出来的data长度为0,len(data)==0
    while len(data)>0:
        data = sock.recv(1024)
        num +=len(data)
        total_data += data       
    with open("11.png","wb") as f:
        f.write(total_data)
    sock.close()
sock.close()
#客户端
import socket 
import struct
import os
import json

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",3008))
print("connect success.....")
filepath = "1.png"
img = open(filepath,"rb")
# print(len(img.read()))

client.sendall(img.read())
img.close()
client.close()

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: 走进 JDK 之 PriorityQueue

下一篇: 用 Navicat Premium 导出表结构和数据

精华推荐