2013-01-10 56 views
0

我有一个客户端服务器通信,我写了下面的服务器来处理传入的消息,但如果消息比缓冲区大,它会丢失。如果消息大于缓冲区大小,我如何收到整个包?有没有可能,或者我不得不强制客户端(在最大缓冲区大小的请求下发送消息)在缓冲区大小内发送消息?Python的TCP缓冲区溢出

msg ='' 
while(True):     
    msg += server.recv(20480)          
    aSplit = msg.partition("</packet>") 
    #We received the full message 
    while(aSplit[ 1 ] == "</packet>"):       
      messagehandler( aSplit[ 0 ] + "</packet>")       
      msg = aSplit[ 2 ] 
      aSplit = msg.partition("</packet>") 

回答

3

当任何一种打包的消息格式的处理,你才真正有两种选择:

  1. 确保你的缓冲区足够大,以应对整个消息。
  2. 编写代码以便它可以解析部分消息。

当我说“缓冲”,不过,我并不意味着recv()参数 - 你可以作出这样的小,只要你喜欢,只是走在你的while循环多次,直到你有一个整个邮件。

因此,采取缓冲方式,你可以做这样的事情:

msg = '' 
while True: 
    msg += server.recv(8192) 
    while True: 
     aSplit = msg.partition("</packet>") 
     if not aSplit[1]: 
      break 
     messagehandler(aSplit[0] + "</packet>") 
     msg = aSplit[2] 

这工作,因为如果</packet>没有找到,那么partition()仍然返回一个3元组,其中第一项是整个字符串另外两个是空的。因此,partition()一直为分隔符返回一个非空字符串,然后发现一个数据包。一旦空了,就会有一个msg中的一部分数据包(或者它是空的),所以我们再回到从网络读取数据,直到我们再次获取整个数据包。

这确实涉及缓冲msg字符串中的整个消息,但这很好,除非您希望这些消息变得非常大(多兆字节) - 例如,如果消息包含大文件,则可能会发生这种情况。在这种情况下,你需要更加聪明,并且做一些事情,比如将数据交换到磁盘,或者在收到数据时处理数据。

让我知道,如果我不清楚任何。

编辑:我应该补充说,一般来说确保缓冲区(即msg)不会变得太大是个好主意 - 如果这样做,那么您需要关闭连接,因为出现了问题。这会停止为应用程序提供无尽的数据,直到内存在系统上耗尽,无论是意外还是恶意。此外,您需要确保字符串</packet>实际上不会发生在邮件内部 - 这会错误地将邮件分成一半。

+0

当我发送100KB的消息时,我仍然失去了消息的结尾 –

+0

这听起来像是超出了操作系统的缓冲区来存储数据。例如,如果您使用的是TCP连接,则可以发送的数据量是有限的 - 无论您的客户在做什么,它都可以一次读取GB,这仍然会发生。你在发送端需要做的事情是注意'send()'的返回码,它会告诉你发送了多少数据。你的应用程序必须继续发送其余的循环,直到它全部发送完毕。我建议你阅读[Python sockets HOWTO](http://docs.python.org/2/howto/sockets.html)。 – Cartroo

+0

特别是,阅读[使用套接字]一节(http://docs.python.org/2/howto/sockets.html#using-a-socket) - 我引用:*现在我们来到主要的绊脚石的套接字 - send和recv在网络缓冲区上运行。他们不一定处理你交给他们的所有字节(或者期望他们),因为他们的主要焦点是处理网络缓冲区。* – Cartroo