2016-02-23 103 views
1

简短说明:Python TCP套接字数据有时会丢失部分。套接字溢出?

客户端通过TCP套接字发送服务器数据。数据长度不同,并且是由分隔符分割的字符串“~~~ * ~~~”

大多数情况下,它工作正常。一段时间。几分钟之后,数据即将全面释放。所以我开始跟踪这个问题,数据在错误的地方结束了,因为整个事情还没有通过。

一切都进入服务器脚本,并由不同的分隔符分析- 新数据 - 然后放入队列。这是代码:

是的我知道缓冲区的大小是巨大的。不,我不会一次性发送那种大小的数据,但我正在与它一起玩耍。

class service(SocketServer.BaseRequestHandler): 
    def handle(self): 
     data = 'dummy' 

     #print "Client connected with ", self.client_address 
     while len(data): 
      data = self.request.recv(163840000) 
      #print data 
      BigSocketParse = [] 
      BigSocketParse = data.split('*-New*Data-*') 

      print "Putting data in queue" 
      for eachmatch in BigSocketParse: 
       #print eachmatch 
       q.put(str(eachmatch)) 

      #print data 
      #self.request.send(data) 

     #print "Client exited" 
     self.request.close() 


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 
    pass 

t = ThreadedTCPServer(('',500), service) 
t.serve_forever() 

然后我有一个线程上运行,而不是q.empty():其中由其他分隔符解析数据“~~~ * ~~~”

所以这个工程的一段时间。我要发送的数据类型的示例:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42 
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com 
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~~~-15 

但事情开始中断。所以我采取了一些控制数据,并在一个循环中发送。会工作一段时间,然后结果开始在错误的地方清盘。并且这在我的队列中出现:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42 
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com 
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~ 

删去最后一个“~~ -15”。

因此,完全相同的数据工作,然后以后不会。这对我来说意味着某种溢出。

客户端连接是这样的:

class Connect(object): 

    def connect(self): 
     host = socket.gethostname() # Get local machine name 
     #host = "127.0.0.1" 
     port = 500    # Reserve a port for your service. 
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     #print('connecting to host') 
     sock.connect((host, port)) 
     return sock 

    def send(self, command): 
     sock = self.connect() 
     #recv_data = "" 
     #data = True 

     #print('sending: ' + command) 
     sock.sendall(command) 
     sock.close() 
     return 

它不会等待响应,因为我不希望它挂在等待一个做。但是它关闭了套接字,并且(据我所知),我不需要刷新套接字缓冲区,也不需要在连接关闭时自行清除它。

真的很感谢任何帮助。这一点让我有点空闲。

更新:

我我的本地机器和一个漂亮结实的服务器上运行这一点,我会推到相信这是一个硬件问题。服务器/客户端既在本地运行,也使用套接字作为他们进行通信的方式,所以我不认为延迟会是原因。

我一直在阅读与TCP通信的问题。我觉得我会很快超出我的深度,但我开始怀疑它是不是一个溢出,但只是一些拥挤的王。

如果客户端的sendall不能确保发送所有内容,那么可能需要在服务器端进行某种计时器/检查,以确保没有更多事情即将到来。

+0

套接字缓冲是有可能的解释 - 我遇到了这个问题,有一个实用程序从C++程序接收数据。在我这边,问题在于处理每封邮件花费的时间太长。为了解决这个问题,我们必须修改我的客户端,以便在子进程完全读取并填充队列的情况下使用多处理。这使我可以在缓冲区溢出之前清除缓冲区。执行解析/处理必须在与接收分开的过程中进行。 –

+0

感谢您抽出时间。似乎移动得更快,但完全相同的错误发生在完全相同的地方。将使用线程代码示例更新问题。 – PoweredByCoffee

+0

@PoweredByCoffee嘿你有没有想到这一点。我有完全相同的问题。我的TCP服务器接收数据(使用我的自定义分隔符)约15-20分钟,然后突然无法找到任何分隔符。数据仍然在收到。无论如何,如果你有解决方案,我会很感激。谢谢。 – PhilBot

回答

3

的基本问题是您:

data = self.request.recv(163840000) 

线保证获得一次所有数据(不管你有多大使缓冲)。

为了正常工作,您必须处理一次没有获取所有数据的情况(您需要跟踪您的位置并追加到它)。请参阅相关的例子在Python docs on using a socket

现在我们就来插座的主要绊脚石 - send和recv在网络缓冲区操作。他们不一定处理你交给他们的所有字节(或者他们期望的),因为他们的主要焦点是处理网络缓冲区。一般来说,它们在关联的网络缓冲区被填充(发送)或清空(recv)时返回。然后他们会告诉你他们处理了多少字节。您有责任再次打电话给他们,直到您的信息完全处理完毕。

2

如上所述,即使您有较大的缓冲区大小,您仍未收到完整的消息。你需要继续接收,直到你得到零字节。您可以编写自己的发电机,该发电机采用request对象并生成零件。漂亮的一面是,你就可以开始处理邮件,而一些仍在

def recvblocks(request): 
    buf = '' 
    while 1: 
     newdata = request.recv(10000) 
     if not newdata: 
      if buf: 
       yield buf 
      return 
     buf += newdata 
     parts = buf.split('*-New*Data-*') 
     buf = parts.pop() 
     for part in parts: 
      yield part 

来,但你需要在客户端上的修复也。您需要关闭套接字之前接近真正关闭TCP连接

sock.sendall(command) 
    sock.shutdown(request.SHUT_RDWR) 
    sock.close()