2013-08-22 68 views
1

我不知道,如果這個主題已經回答與否,如果是不好意思: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

回答

2

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

相關問題