2010-07-06 191 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())