Python客户端/服务器发送的大尺寸文件

问题描述:

我不知道,如果这个主题已经回答与否,如果是不好意思:Python客户端/服务器发送的大尺寸文件

我有一个简单的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 ...),它会崩溃,因为客户端等待服务器的时间是不够的。

所以我的问题是我怎么能发送文件到服务器,而无需客户端需要等待?或确切地知道客户端需要等待服务器接收文件多少时间?一些相同的代码,但处理任何文件大小,有什么帮助?

+0

是的我知道python不需要“;”和“()”,但我喜欢这样做! – lazyy001

+1

嗯,它让你的代码难以阅读,因为有经验的Python开发人员 - 你想在这里帮助你的人。 – abarnert

+0

同时,'if(data.endswith(end)):'不会起作用,因为结束标记可能来自数据包中的_anywhere_,而不仅仅是数据包的末尾。 (如果你想发送的文件中出现“292929”字符串,例如,如果你尝试发送一个包含这个脚本的目录,那么这也将是一个大问题。) – abarnert

TCP sockets are byte streams, not message streams。如果你想发送一系列单独的消息(比如你的单独文件),你需要定义一个协议,然后编写一个协议处理程序。这是没有办法的;只是在猜测时间或试图利用数据包边界不可能工作。

上面链接的博客文章显示了一种方法。但是,如果你愿意,你可以用字符串分隔符来完成。但是你必须处理两个问题:

  • 定界符可以出现在read数据包中的任何地方,而不仅仅是结尾。
  • 分隔符可以在数据包边界上分开 - 您可以在一次读取结束时获得"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] 

同时,你有你的分隔符另一个问题:没有什么出现在你试图传送文件停止它。例如,如果您尝试发送您的脚本或此网页,该怎么办?

这是其他协议通常比分隔符更好的原因之一,但这并不难处理:只需转义在文件中找到的任何分隔符即可。由于您一次发送整个文件,因此您可以在sendall之前恰好使用replace,在split之前恰好使用replace

+0

非常感谢,我想我会在所有的代码中看起来更好,看看最好的方法来使它工作!我知道上面的代码只是一个大混乱! – lazyy001