2010-07-06 186 views
4

我想寫一個安全的傳輸文件程序使用Python和AES,我有一個問題,我不完全明白。我通過使用1024字節的塊來解析文件併發送它們,但接收數據的服務器端發生崩潰(我使用AES CBC,因此我的數據長度必須是16字節的倍數),並且我得到的錯誤表示它是不。TCP套接字文件傳輸

我試圖打印客戶端發送的數據的長度和客戶端接收到的數據的長度,它表明客戶端每次發送的時間恰好是它應該發送的1024字節,但是服務器端顯示在某個時間點接收到的數據包不是並且小於1024字節(例如743字節)。

我試圖把客戶端發送每個套接字之間的time.sleep(0.5),它似乎工作。是否有可能是服務器端的某種套接字緩衝區故障?客戶端發送的太多數據太快,並且它在服務器端以某種方式中斷了套接字緩衝區,導致數據被破壞或消失,並且recv(1024)僅接收到一個破碎的數據塊?這是我能想到的唯一的事情,但是這也可能是完全錯誤的,如果任何人有,爲什麼這不能正常工作,那就太棒了的想法;)

按照我的想法我想:

self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000) 
    print socket.SO_RCVBUF 

我試圖把一個32mbytes的緩衝區放在服務器端,但在Windows XP上它顯示4098的打印和Linux上它只顯示了8.我不知道我該如何解釋這一點,我唯一知道的是它似乎它沒有32mbytes的緩衝區,所以代碼不起作用。

好吧,這是一個非常長的帖子,我希望你們中的一些人有勇氣把它全部讀到這裏!我完全失去了存在,如果任何人有對此問題的任何想法,請與大家共享:d

感謝費薩爾我的代碼是在這裏:

服務器端:(計數是我的文件大小/ 1024)

while 1: 
    txt=self.s.recv(1024) 
    if txt == " ": 
     break  
    txt = self.cipher.decrypt(txt) 
    if countbis == count: 
     txt = txt.rstrip() 
    tfile.write(txt) 
    countbis+=1 

客戶端:

while 1: 
    txt= tfile.read(1024) 
    if not txt: 
     self.s.send(" ") 
     break 
    txt += ' ' * (-len(txt) % 16) 
    txt = self.cipher.encrypt(txt) 
    self.s.send(txt) 

由於提前,

Nolhian

+1

如果您將代碼發佈到recv()調用的周圍,那麼找出錯誤會更容易一些。假設你每次傳輸調用一次recv(),你應該知道你不能期望在一次調用recv()的時候獲得你發送的所有數據的1024個字節。您需要循環調用recv()並連接到緩衝區,直到您收到您期望的1024個字節。 – Faisal 2010-07-06 20:19:56

回答

8

歡迎來到網絡編程!你剛剛陷入了同樣的錯誤的假設,即大家第一次通過假設客戶端發送&服務器recives應該是對稱的。不幸的是,這種情況並非如此。操作系統允許接收發生在任意大小的塊中。儘管這樣做很容易,只是緩衝你的數據,直到你讀入的數量等於你希望收到的數額。沿此線的東西就可以了:

buff='' 
while len(buff) < 1024: 
    buff += s.recv(1024 - len(buff)) 
+1

對不起,但我沒有陷入這個(可能是因爲我在使用代碼編寫我的第一個套接字之前閱讀了很多代碼和Steven的網絡編程書)。也許你需要改變_所有人_幾乎每個人_。 ;-P – ninjalj 2010-07-06 20:43:19

+0

非常感謝解釋!此外,我已將您的線路應用到我的程序中,並且現在完美地工作;) – Nolhian 2010-07-06 21:29:39

3

TCP是一種流協議,它不會像以前發現的那樣節省消息邊界。

1

什麼TCP可以保證的是,所有的數據到達時,按照正確的順序,在某些時候。 (除非意外發生,否則它不會到達。)但是,您發送的數據很可能仍會以大塊的形式出現。其中很大一部分是因爲發送緩衝區和接收緩衝區有限。你應該做的是繼續做你的recv調用,直到你有足夠的數據來處理它。您可能需要多次撥打send;使用它的返回值來跟蹤到目前爲止發送/緩衝了多少數據。

當你做print socket.SO_RCVBUF,你居然打印符號SO_RCVBUF 含量的不同(除了Python並不真的有常數);用來告訴setsockopt你想改變什麼。要獲得當前值,您應該撥打getsockopt

+0

謝謝,這與Rakis的答案一起幫助很大。我試圖將你的答案設置爲Rakis的答案,但似乎我只能設置一個答案,這太糟糕了:( – Nolhian 2010-07-06 21:39:18

2

正如其他人指出,你可能正在處理一個不完整的消息。你需要有固定大小的消息或者有一個分隔符(不要忘記逃離你的數據!),這樣你就知道何時收到完整的消息。

0

對於許多應用程序,TCP的複雜性被Python的asynchat模塊整齊地抽象出來。

+0

)你的回答是真實的,但對目前的簡潔格式沒有什麼幫助;如果你用一個例子,我會贊成,其他人也可能會(或許) – tzot 2010-07-07 13:05:27

+0

考慮到'asynchat'是90年代後期的標準庫編程的一個非常不幸的例子,它從來沒有人真正使用過,即使解釋它也不會得到任何讚揚! ) – 2013-01-16 16:54:58

1

與TCP無關(因爲已經得到了回答),但是如果您期望收到很多,則重複附加到字符串將效率低下。最好追加到列表中,然後在使用''.join(list)完成接收時將列表轉換爲字符串。

0

如上

TCP提的是流協議

你可以試試這個代碼,其中的數據是原始的數據,你可以從文件或用戶輸入讀取它

發件人

import socket as s 
sock = s.socket(s.AF_INET, s.SOCK_STREAM) 
sock.connect((addr,5000)) 
sock.sendall(data) 
finish = t.time() 

接收機

import socket as s 
sock = s.socket(s.AF_INET, s.SOCK_STREAM) 
sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1) 
sock.bind(("", 5000)) 
sock.listen(1) 
conn, _ = sock.accept() 
pack = [] 
while True: 
    piece = conn.recv(8192) 
    if not piece: 
     break 
    pack.append(piece.decode())