避免TCP / IP连接挂起

时间:2015-05-20 23:16:59

标签: python sockets hang tcp-ip

我正在使用Python socket包通过TCP / IP与乐器进行通信。

程序向仪器发送命令以执行操作,然后重复发送另一个“检查”命令,直到它收到“完成”回复。但是,经过多次循环后,程序会在等待“完成”回复时挂起。

我已经使用下面的recv_timeout()函数规避了这个问题,如果套接字挂起则不返回任何数据,然后我关闭与socket.close()的连接并重新连接。

是否有更优雅的解决方案而无需重启任何东西?

    import socket
    import time

    def recv_timeout(self,timeout=0.5):
         '''
         code from http://code.activestate.com/recipes/408859/
         '''
         self.s.setblocking(0)
         total_data=[];data='';begin=time.time()
         while 1:There must be a way I can reboot to carry on communicating with the instrument, without having to restart.   
             #if you got some data, then break after wait sec
             if total_data and time.time()-begin>timeout:
                 break
             #if you got no data at all, wait a little longer
             elif time.time()-begin>timeout*2:
                 break
             try:
                 data=self.s.recv(8192)
                 if data:
                      total_data.append(data)
                      begin=time.time()
             else:
                 time.sleep(0.1)
             except:
                 pass
         return ''.join(total_data)

    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect(('555.555.55.555',23))

    for action_num in range(0,1000):
         socket.sendall(('performaction %s \r'%action_num).encode())

         while True:
              time.sleep(0.2) 
              socket.sendall(('checkdone \r').encode())
              done = socket.recv_timeout()  
              if not done:
                   print 'communication broken...what should I do?'
                   socket.close()
                   time.sleep(60)
                   sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                   sock.connect(('555.555.55.555',23))
              elif done == '1':
                   print 'done performing action'
                   break  
    socket.close()    

1 个答案:

答案 0 :(得分:1)

  

我通过使用recv_timeout()函数来规避这个问题   在下面,如果套接字挂起则不返回数据

你确定套接字会永远挂起吗?那么仪器有时需要超过半秒的时间才能响应? (请注意,即使仪器的软件能够及时响应,也不能保证响应数据能够及时到达您的Python程序。例如,如果TCP数据包包含响应被网络丢弃并且必须重新发送,这可能导致它们花费超过0.5秒的时间返回到您的程序。您可以通过将以太网电缆从PC中拉出一两秒来强制执行该方案然后将其重新插入......你会看到响应字节仍然通过,只是一两秒钟后(在丢弃的数据包重新发送之后);也就是说,如果你的Python程序没有&# 39;放弃它们并关闭套接字。

  

是否有更优雅的解决方案而无需重启任何东西?

优雅的解决方案是弄清楚故障场景中的回复字节发生了什么,并修复底层错误,以便回复字节不再丢失。 WireShark可以非常有助于诊断故障的位置;例如,如果WireShark显示响应字节确实进入了您计算机的以太网端口,那么这是一个非常好的线索,即该错误在您的Python程序中处理传入的字节(*)。另一方面,如果响应字节永远不会出现在WireShark中,那么仪器本身可能存在一个错误,导致它有时无法响应。 Wireshark还会告诉你,如果问题是你的Python脚本未能发出"检查"因某种原因命令。

那就是说,如果你真的无法修复底层错误(例如,因为它是仪器中的一个错误而你无法升级运行的软件的源代码仪器)然后你唯一能做的就是你正在做什么 - 关闭套接字连接并重新连接。如果仪器由于某种原因不想回复,则不能强迫它做出回应。

(*)要做的一件事是打印出recv_timeout()返回的字符串的内容。你可能会发现你确实得到了答复,但它并不是“1”和“#1”。你期待的字符串。