下面的代码让我从服务器向客户端下载三个文件,分别是tmp.bsp、tmp.seq 和tmp.dms。然而,只有第一个文件 tmp.dms 被完全下载。另一个tmp.seq填充了tmp.bsp的信息,tmp.bsp保持0KB。
客户:
import socket
import socket
skClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
skClient.connect(("127.0.0.1",2525))
sData = "Temp"
sData2 = "Temp"
sData3 = "Temp"
while True:
sData = skClient.recv(1024)
fDownloadFile = open("tmp.dms","wb")
sData2 = skClient.recv(1024)
fDownloadFile2 = open("tmp.seq","wb")
sData3 = skClient.recv(1024)
fDownloadFile3 = open("tmp.bsp","wb")
while sData:
fDownloadFile.write(sData)
sData = skClient.recv(1024)
fDownloadFile.close()
fDownloadFile2.write(sData2)
sData2 = skClient.recv(1024)
fDownloadFile2.close()
fDownloadFile3.write(sData3)
sData3 = skClient.recv(1024)
fDownloadFile3.close()
print "Download over"
break
skClient.close()
n
是一个计数器,输出用于调试。
sFileName
是下载一个文件,曾经可以工作,但因为我想要三个文件,所以我只是评论了它。
服务器:
import socket
host = ''
skServer = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
skServer.bind((host,2525))
skServer.listen(10)
print "Server currently active"
while True:
Content,Address = skServer.accept()
print Address
files = "C:\Users\Name_user\Desktop\Networking\Send_Receive/"
fUploadFile = open(files+str('tmp.dms'),"rb")
sRead = fUploadFile.read(1024)
fUploadFile2 = open(files+str('tmp.seq'),"rb")
sRead2 = fUploadFile2.read(1024)
fUploadFile3 = open(files+str('tmp.bsp'),"rb")
sRead3 = fUploadFile3.read(1024)
while sRead:
Content.send(sRead)
sRead = fUploadFile.read(1024)
Content.send(sRead2)
sRead2 = fUploadFile2.read(1024)
# Content.send(sRead3)
# sRead3 = fUploadFile3.read(1024)
Content.close()
print "Sending is over"
break
skServer.close()
我正在使用的文件:
server2.py is my server
Execution
最佳答案
您的代码的主要问题是您正在发送/接收任意数量的数据。如果您的缓冲区 (1024) 小于文件大小,则客户端文件将包含较少信息,如果缓冲区较大,则文件可能包含更多信息(来自下一个文件的数据)。
您可以通过发送一个表示文件结束的值来解决这个问题。这种方法的问题是这个值不能包含在任何文件中,客户端必须扫描接收到的数据来寻找这个值。
另一种可能的解决方案是计算文件大小并将该信息发送到文件数据之前。这样,客户就会知道每个文件需要多少数据。
使用 struct.pack
我们可以创建一个包含文件大小的最小四字节 header 。
def send_file(soc, path):
with open(path, 'rb') as f:
data = f.read()
size = struct.pack('!I', len(data))
soc.send(size + data)
然后客户端可以通过读取四个字节和unpack
得到文件大小荷兰国际集团诠释。
def recv_file(soc, path):
size_header = soc.recv(4)
size = struct.unpack('!I', size_header)[0]
data = soc.recv(size)
with open(path, 'wb') as f:
f.write(data)
请注意,如果文件大小大于套接字缓冲区,则使用一次调用发送/接收文件可能会引发套接字错误。在这种情况下,您必须在循环中以较小的 block 读取数据,或者使用 socket.setsockopt
增加缓冲区大小.
这是可以处理大文件的上述函数的修改版本:
import struct
import os.path
def send_file(soc, path):
file_size = os.path.getsize(path)
size_header = struct.pack('!Q', file_size)
soc.send(size_header)
with open(path, 'rb') as f:
while True:
data = f.read(1024)
if not data:
break
soc.send(data)
def recv_file(soc, path):
size_header = soc.recv(8)
file_size = struct.unpack('!Q', size_header)[0]
chunks = [1024 for i in range(file_size / 1024)]
with open(path, 'wb') as f:
for chunk in chunks:
f.write(soc.recv(chunk))
f.write(soc.recv(file_size % 1024))
我还没有彻底测试这段代码,但它应该适用于任何大小的文件。
在您的服务器中使用 send_file
函数的示例:
host = ''
skServer = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
skServer.bind((host,2525))
skServer.listen(10)
print "Server currently active"
Content,Address = skServer.accept()
print Address
files = ['tmp.bsp', 'tmp.seq', 'tmp.dms']
for file in files:
send_file(Content, file)
Content.close()
print "Sending is over"
skServer.close()
在客户端使用recv_file
:
skClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
skClient.connect(("127.0.0.1",2525))
files = ['tmp.bsp', 'tmp.seq', 'tmp.dms']
for file in files:
recv_file(skClient, file)
print "Download over"
skClient.close()
关于python - 从本地服务器下载多个文件到客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50976915/