Python TCP设备不会结束连接,单个设备会结束许多非活动连接
我有一个奇怪的问题如下 我正在用Python2.7准备一个设备客户端。有一些跟踪设备处于活动状态并正在运行,向服务器发送信号。它们有周期性信号,每小时发送一次。信号发送频率根据情况而变化,但他们必须每小时至少发送一次GPS位置数据信号 这些设备正在长连接模式下运行,这意味着设备启动的连接应保持活动状态3-4小时。为了保持这种连接,你发送的心跳信号不是GPS位置信号,而是包含一些数据的信号。心跳信号间隔为15分钟 下面是我监听TCP端口的脚本Python TCP设备不会结束连接,单个设备会结束许多非活动连接,python,python-2.7,sockets,tcp,Python,Python 2.7,Sockets,Tcp,我有一个奇怪的问题如下 我正在用Python2.7准备一个设备客户端。有一些跟踪设备处于活动状态并正在运行,向服务器发送信号。它们有周期性信号,每小时发送一次。信号发送频率根据情况而变化,但他们必须每小时至少发送一次GPS位置数据信号 这些设备正在长连接模式下运行,这意味着设备启动的连接应保持活动状态3-4小时。为了保持这种连接,你发送的心跳信号不是GPS位置信号,而是包含一些数据的信号。心跳信号间隔为15分钟 下面是我监听TCP端口的脚本 class Server(object): d
class Server(object):
def __init__(self, host, sock_port, buffsize=1024):
self.hostname = host
self.sock_port = sock_port
self.buffsize = buffsize
self.socket = None
def start(self):
self.log.info("Listening: ")
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((self.hostname, self.sock_port))
self.socket.listen(1024)
while True:
conn, address = self.socket.accept()
thread.start_new_thread(GV55LiteHandler(conn=conn, buff_size=self.buffsize).handle_data, ())
这是套接字服务器接收新连接时调用的方法:
class GV55LiteHandler():
....
def handle_data(self):
while True:
try:
_veri = self.conn.recv(self.buff_size)
if not _veri:
# We do not recieve any data...
raise NoIncomingDataException()
except NoIncomingDataException:
break
except Exception as h_e:
print h_e
break
else:
self.control_data(_veri)
self.conn.close()
过了一会儿,我使用psutil检查进程的线程数,发现线程总数大于5.000。我评估这一点是因为有些设备的死连接看起来仍然处于活动状态,但被设备断开,并建立了新连接。考虑到总数,每个设备看起来像创建了4个连接,当设备内的长连接时间设置过多时关闭它们,并建立了一个新连接。这在某些情况下是正常的,没有效果。但是过了一段时间,我收到报告说有些设备无法连接!然后我杀死端口侦听脚本并重新启动它,在10分钟内,所有无法连接和发送数据的设备都会再次开始发送数据。对此进行了一些研究,但找不到任何有关情况的信息。我最好的猜测是,在一个设备建立了太多的连接后,我有一个类似的跟踪设备与另一个制造商,我有大约120个活动设备,看到的线程总数为1600个,这意味着每个设备都建立了连接,但未能断开10个以前的连接,然后建立一个全新的连接,就像以前的一样服务器不接受来自该设备的任何新连接,或者设备无法创建到服务器的新TCP连接,并且GPS数据在脚本重新启动和所有连接断开之前不会发送
这些跟踪设备在单个数据连接上运行。这意味着,任何设备都不能有2个活动数据连接,使用这两个连接发送数据也没有意义
我尝试将TCP连接超时设置为TCP连接,如下所示:
conn, address = self.socket.accept()
conn.settimeout(10800)
并在数据处理脚本中处理此问题:
try:
_veri = self.conn.recv(self.buff_size)
if not _veri:
# We do not recieve any data...
raise NoIncomingDataException()
except NoIncomingDataException:
# No need to log anything in here...
break
except socket_timeout:
print "Socket Timeout"
break
这似乎是可行的,现在我没有任何设备,不能发送GPS数据。但另一方面,conn.settimeout没有正确设置连接超时,在一段时间后,在最后一个信号发出30秒后,连接被conn.settimeout超时。我希望它将超时设置为3小时,但它失败了,连接在大约20分钟后中断,并发送一个新的心跳信号以打开新连接,然后是GPS位置信号。GPS信号必须每小时发送一次,但当设置超时时,我每20分钟收到一次信号
我使用阻塞套接字作为默认套接字行为。不要尝试非阻塞套接字,也不要太了解它们
我如何才能摆脱导致设备不发送数据的非活动连接,而不中断设备的长连接模式
更新:在settimeout版本和no timeout版本中,我从未在handle_数据方法中遇到NoIncomingDataException
更新2:我的服务器中有Debian GNU/Linux 6.0.10。
My/etc/sysctl.conf配置:
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_ecn = 0
上面的python行是唯一配置套接字的,因此我只有setsockoptsocket.SOL_socket,socket.SO_REUSEADDR,1。我在python脚本中没有socket.SO的任何配置。\u KEEPALIVE。至少,如果遇到raise NoIncomingDataException或任何其他异常,您似乎从未调用self.conn.close-因此请确保没有泄漏连接。另外,self.conn.recv是否检测到丢失的心跳?你需要一些方法来检测一个死客户端,这样你就可以关闭它的连接——从代码中看不出你是这么做的。不,我从来没有遇到过这个异常。奇怪的是,这20分钟看起来像一些系统上默认的TCP keepalive超时75000秒。您能否检查套接字上是否启用了TCP keepalive,即您正在使用的操作系统?。如果没有,请尝试启用它。如果启用了该选项,则可以尝试使用较低的值。我需要查找这个,但我非常确定settimeout只影响阻塞操作,它不会在超时后关闭套接字。@谢谢,问题已更新