TCP Socket 文件传输
我正在尝试使用 Python 和 AES 编写一个安全传输文件程序,但我遇到了一个我不完全理解的问题。我通过用 1024 字节块解析文件并将其发送过来来发送文件,但接收数据的服务器端崩溃(我使用 AES CBC,因此我的数据长度必须是 16 字节的倍数),我得到的错误表明它是不是。
我尝试在客户端打印客户端发送的数据的长度以及在服务器上接收的数据的长度,它显示客户端每次都像预期的那样发送 1024 字节,但服务器端显示在某个时间点,收到的数据包不是,因此小于 1024 字节(例如 743 字节)。
我尝试在客户端发送的每个套接字之间放置一个 time.sleep(0.5) ,它似乎有效。是否有可能是服务器端的某种套接字缓冲区故障?客户端发送的数据太多,速度太快,并且以某种方式破坏了服务器端的套接字缓冲区,因此数据被损坏或消失,而 recv(1024) 只收到损坏的块?这是我唯一能想到的事情,但这也可能是完全错误的,如果有人知道为什么这不能正常工作那就太好了;)
按照我的想法我尝试过:
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000)
print socket.SO_RCVBUF
我试图在服务器端,但在Windows XP上它在打印上显示4098,在Linux上它只显示8。我不知道我必须如何解释这个,我唯一知道的是它似乎没有32兆字节的缓冲区,所以该代码不起作用。
这是一篇非常长的文章,我希望你们中的一些人有勇气读到这里!我完全迷失了所以如果有人对此有任何想法请分享:D
感谢 Faisal 我的代码在这里:
服务器端:(计数是我的文件大小/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
I'm trying to write a secure transfer file program using Python and AES and i've got a problem i don't totally understand. I send my file by parsing it with 1024 bytes chunks and sending them over but the server side who receive the data crashes ( I use AES CBC therefore my data length must be a multiple of 16 bytes ) and the error i get says that it is not.
I tried to print the length of the data sent by the client on the client side and the length of the data received on the server and it shows that the client is sending exactly 1024 bytes each time like it's supposed to, but the server side shows that at some point in time, a received packet is not and so less than 1024 bytes ( for example 743 bytes ).
I tried to put a time.sleep(0.5) between each socket send on the client side and it seems to work. Is it possible that it is some kind of socket buffer failure on the server side ? That too much data is being send too fast by the client and that it breaks somehow the socket buffer on the server side so the data is corrupted or vanish and the recv(1024) only receive a broken chunk? That's the only thing i could think of, but this may also be completely false, if anyone has an idea of why this is not working properly it would be great ;)
Following my idea i tried :
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000)
print socket.SO_RCVBUF
I tried to put a 32mbytes buffer on the server side but On Windows XP it shows 4098 on the print and on linux it shows only 8. I don't know how i must interpret this, the only thing i know is that it seems that it doesn't have a 32mbytes buffer so the code doesn't work.
Well it's been a really long post, i hope some of you had the courage to read it all to here ! i'm totally lost there so if anyone has any idea about this please share it :D
Thanks to Faisal my code is here :
Server Side: ( count is my filesize/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
Client side :
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)
Thanks in advance,
Nolhian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
欢迎来到网络编程!您刚刚陷入了同样的错误假设,即每个人第一次都会假设客户端发送&服务器接收应该是对称的。不幸的是,事实并非如此。操作系统允许以任意大小的块进行接收。不过,解决方法相当容易,只需缓冲数据,直到您读取的数据量等于您希望接收的数据量即可。类似这样的事情就可以解决问题:
Welcome to network programming! You've just fallen into the same mistaken assumption that everyone makes the first time through in assuming that client sends & server recives should be symmetric. Unfortunately, this is not the case. The OS allows reception to occur in arbitrarily sized chunks. It's fairly easy to work around though, just buffer your data until the amount you've read in equals the amount you wish to receive. Something along the lines of this will do the trick:
TCP 是一种流协议,正如您刚刚发现的那样,它不保留消息边界。
TCP is a stream protocol, it doesn't conserve message boundaries, as you have just discovered.
正如其他人指出的那样,您可能正在处理一条不完整的消息。您需要具有固定大小的消息或具有分隔符(不要忘记转义您的数据!),以便您知道何时收到完整的消息。
As others have pointed out you're probably processing an incomplete message. You need to either have fixed sized messages or have a delimiter (don't forget to escape your data!) so you know when a complete message has been received.
TCP 可以保证的是,所有数据都会在某个时刻以正确的顺序到达。 (除非发生意外情况,导致数据无法到达。)但是您发送的数据很可能仍会分块到达。这很大程度上是因为发送和接收缓冲区有限。您应该做的是继续执行
recv
调用,直到有足够的数据来处理它。您可能需要多次调用send
;使用其返回值来跟踪到目前为止已发送/缓冲的数据量。当你
print socket.SO_RCVBUF
时,你实际上打印了符号SO_RCVBUFcontant(除了Python实际上没有常量);用于告诉setsockopt
您想要更改的内容。要获取当前值,您应该调用getsockopt
。What TCP can guarantee is that all your data arrives, in the right order, at some point. (Unless something unexpected happens, by which it won't arrive.) But it's very possible that the data you send will still arrive in chunks. Much of it is because of limited send- and receive-buffers. What you should do is to continue doing your
recv
calls until you have enough data to process it. You might might have to callsend
multiple times; use its return value to keep track of how much data has been sent/buffered so far.When you do
print socket.SO_RCVBUF
, you actually print the symbolic SO_RCVBUF contant (except that Python doesn't really have constants); the one used to tellsetsockopt
what you want to change. To get the current value, you should instead callgetsockopt
.与 TCP 无关(因为已经回答了),但是如果您期望收到很多数据,则重复附加到字符串将相当低效。最好附加到列表,然后在完成接收后使用
''.join(list)
将列表转换为字符串。Not related to TCP (as that has been answered already), but appending to a string repeatedly will be rather inefficient if you're expecting to receive a lot. It might be better to append to a list and then turn the list into a string when you finished receiving by using
''.join(list)
.对于许多应用程序来说,Python 的 asynchat 模块巧妙地抽象了 TCP 的复杂性。
For many applications, the complexities of TCP are neatly abstracted by Python's asynchat module.
这是我前段时间编写的一段不错的代码,可能不是最好的,但它可能是通过本地网络传输大文件的好例子。 http://setahost.com/sending-files-in-local-网络与Python/
Here is the nice snippet of code that I wrote some time ago, may be not the best , but it could be good example of big files transfer over the local network. http://setahost.com/sending-files-in-local-network-with-python/
如上所述
你可以试试这个代码,其中的数据是你的原始数据,你可以从文件或用户输入中
读取
它
As mentioned above
You can try this code, where the data is your original data, you can read it from the file or user input
Sender
Receiver