我不确定这个主题是否已得到解答,如果是的话,我很抱歉:
我有一个简单的 python 脚本,用于发送一个文件夹中的所有文件:
客户:
import os,sys, socket, time
def Send(sok,data,end="292929"):
sok.sendall(data + end);
def SendFolder(sok,folder):
if(os.path.isdir(folder)):
files = os.listdir(folder);
os.chdir(folder);
for file_ in files:
Send(sok,file_);#Send the file name to the server
f = open(file_, "rb");
while(True):
d = f.read();#read file
if(d == ""):
break;
Send(sok, d, "");#Send file data
f.close();
time.sleep(0.8);#Problem here!!!!!!!!!!!
Send(sok,"");#Send termination to the server
time.sleep(1);#Wait the server to write the file
os.chdir("..");
Send(sok,"endfile");#let the server know that we finish sending files
else:
Send("endfile")#If not folder send termination
try:
sok1 = socket.socket();
sok1.connect(("192.168.1.121",4444))#local ip
time.sleep(1);
while(True):
Send(sok1,"Enter folder name to download: ");
r = sok1.recv(1024);
SendFolder(sok1,r);
time.sleep(0.5);
except BaseException, e:
print "Error: " + str(e);
os._exit(1);
服务器:
import sys,os,socket,time
# receive data
def Receive(sock, end="292929"):
data = "";
while(True):
if(data.endswith(end)):
break;
else:
data = sock.recv(1024);
return data[:-len(end)];#return data less termination
def FolderReceive(sok):
while(True):
r = Receive(sok);# recv filename or folder termination("endfile")
if(r == "endfolder"):
print "Folder receive complete.";
break;
else:
filename = r;#file name
filedata = Receive(sok);# receive file data
f = open(filename,"wb");
f.write(filedata);
f.close();#finish to write the file
print "Received: " + filename;
try:
sok1 = socket.socket();
sok1.bind(("0.0.0.0",4444));
sok1.listen(5);
cl , addr = sok1.accept();#accepts connection
while(True):
r = Receive(cl);
sys.stdout.write("\n" + r);
next = raw_input();
cl.sendall(next);#send folder name to the client
FolderReceive(cl);
except BaseException, e:
print "Error: " + str(e);
os._exit(1);
我知道这不是最好的服务器......但这是我所知道的。这仅适用于包含小文件的文件夹,因为如果我发送大文件(例如 5mb...),它会崩溃,因为客户端等待服务器的时间不够。
所以我的问题是如何将文件发送到服务器而不需要客户端等待?或者确切地知道客户端需要等待服务器接收文件多少时间?一些代码执行相同的操作,但处理任何文件大小,有帮助吗?
最佳答案
TCP sockets are byte streams, not message streams 。如果您想发送一系列单独的消息(例如单独的文件),则需要定义一个协议(protocol),然后编写一个协议(protocol)处理程序。这是没有办法解决的;仅仅猜测时间或尝试利用数据包边界是不可能的。
上面链接的博客文章展示了一种方法。但如果需要,您可以使用字符串分隔符来完成。但你必须处理两个问题:
- 分隔符可以出现在
读取
数据包中的任何位置,而不仅仅是出现在末尾。 - 分隔符可以在数据包边界上分割 - 您可能会在一次读取结束时得到
"2929"
,而在另一次读取开始时得到另一个"29"
接下来。
通常的方法是累积一个缓冲区,并在缓冲区中的任何位置搜索分隔符。像这样的事情:
def message(sock, delimiter):
buf = ''
while True:
data = sock.read(4096)
if not data:
# If the socket closes with no delimiter, this will
# treat the last "partial file" as a complete file.
# If that's not what you want, just return, or raise.
yield buf
return
buf += data
messages = buf.split(delimiter)
for message in messages[:-1]:
yield message
buf = message[-1]
<小时/>
同时,您的分隔符还存在另一个问题:没有什么可以阻止它出现在您尝试传输的文件中。例如,如果您尝试发送脚本或此网页怎么办?
这是其他协议(protocol)通常比分隔符更好的原因之一,但这并不难处理:只需转义文件中找到的任何分隔符即可。由于您要一次发送整个文件,因此您只需在 sendall
之前使用 replace
即可,并在 sendall
之前使用相反的 replace
分割
。
关于Python客户端/服务器发送大尺寸文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18389076/