Python Tornado Websocket连接关闭后仍处于打开状态

Python Tornado Websocket连接关闭后仍处于打开状态,python,websocket,tornado,Python,Websocket,Tornado,我有一个Tornado Websocket服务器,我想在30分钟不活动后超时。我使用self.close()在30分钟不活动后关闭连接。但似乎有些连接即使在关闭后仍保持打开状态 下面是代码的基本部分(从这里获得帮助后实现:): 开放连接: class WebSocketHandler(tornado.websocket.WebSocketHandler): def open(self, *args): self.id = self.generate_id()

我有一个Tornado Websocket服务器,我想在30分钟不活动后超时。我使用
self.close()
在30分钟不活动后关闭连接。但似乎有些连接即使在关闭后仍保持打开状态

下面是代码的基本部分(从这里获得帮助后实现:):

开放连接:

class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def open(self, *args):
        self.id = self.generate_id()
        self.stream.set_nodelay(True)
        # ... DO STUFF ...
        self.ini_time = datetime.now()
        self.message_number = 0
        self.last_message_time = self.ini_time
        self.write_message("Connection SUCCESSFUL! Thanks for connecting! Your connection ID is: %d :)" % self.id)
        self.timeout = tornado.ioloop.IOLoop.current().add_timeout(timedelta(minutes=30), self.force_close)
        print datetime.now()
        print "New connection. ID: %d" % self.id
        print "Total number of open connections: %d" % len(clients)
收到信息时:

    def on_message(self, message):        
        """
        when we receive some message we want some message handler..
        for this example i will just print message to console
        """
        if self.timeout:
            tornado.ioloop.IOLoop.current().remove_timeout(self.timeout)
        self.timeout = tornado.ioloop.IOLoop.current().add_timeout(timedelta(minutes=30), self.force_close)
        self.last_message_time = datetime.now()
        self.message_number+=1

        print datetime.now()
        print "Client %s sent message : %s" % (self.id, message)
        # ... DO STUFF ...
结束时:

def on_close(self):
    self.common_close()

def common_close(self):
    print datetime.now()
    print "Open connections are:"
    print clients.keys()
    print "Closing connection %d." % self.id 

    end = datetime.now()
    timeonline = end - self.ini_time
    timeconlastmsg = self.last_message_time - self.ini_time
    print "Total time online:"
    print timeonline
    print "Time between connection start and last message received:"
    print timeconlastmsg
    if self.id in clients.keys():
        del clients[self.id]
    print "Number of open connections: %d" % len(clients)
    print "Open connections are:"
    print clients.keys()
超时:

def force_close(self):
    timout =  datetime.now()
    print timout
    print "Connection %d timed out, server is dropping the connection." % self.id
    self.common_close()
    self.close() 
超时有效,并调用函数
force\u close
。但是,似乎即使在被调用并从
客户机
中删除连接后,该连接仍处于打开和活动状态

以下是该计划的输出示例:

新连接。身份证号码:66919
打开的连接总数:3
2015-07-14 21:51:48.387892
新连接。身份证号码:12012
打开的连接总数:4
2015-07-14 21:51:48.641603
开放式连接包括:
[66919, 12012, 11281, 97458]
关闭连接66919。
在线总时间:
0:00:00.404316
连接开始和接收到的最后一条消息之间的时间:
0:00:00
打开的连接数:3
开放式连接包括:
[12012, 11281, 97458]
... ...
打开的连接数:4
开放式连接包括:
[66246, 12012, 97458, 6069]
2015-07-14 22:21:47.906129
连接97458超时,服务器正在断开连接。
2015-07-14 22:21:47.906167
开放式连接包括:
[66246, 12012, 97458, 6069]
关闭接头97458。
在线总时间:
0:30:00.000450
连接开始和接收到的最后一条消息之间的时间:
0:00:00
打开的连接数:3
开放式连接包括:
[66246, 12012, 6069]
2015-07-14 22:21:48.237407
连接66919超时,服务器正在断开连接。
2015-07-14 22:21:48.237444
开放式连接包括:
[66246, 12012, 6069]
关闭连接66919。
在线总时间:
0:30:00.000143
连接开始和接收到的最后一条消息之间的时间:
0:00:00
打开的连接数:3
可以看出,66919每隔30分钟“关闭”两次。有什么想法吗

连接3358在假定不再有打开的连接时关闭的另一个示例(再次关闭两次,间隔30分钟):

打开的连接包括:
[7046, 16287]
2015-07-15 11:01:13.604125
新连接。身份证号码:3358
打开的连接总数:3
2015-07-15 11:01:28.429574
开放式连接包括:
[7046, 3358, 16287]
关闭连接3358。
在线总时间:
0:00:14.825568
连接开始和接收到的最后一条消息之间的时间:
0:00:00
打开的连接数:2
开放式连接包括:
[7046, 16287]
--
开放式连接包括:
[]
2015-07-15 11:31:13.629530
连接3358超时,服务器正在断开连接。
2015-07-15 11:31:13.629586
开放式连接包括:
[]
关闭连接3358。
在线总时间:
0:30:00.025556
连接开始和接收到的最后一条消息之间的时间:
0:00:00
打开的连接数:0
开放式连接包括:
[]

有人指出,我不应该在
强制关闭
中调用
common\u close
,因为
on\u close
将被
self.close()
调用,但是
on\u close()
不会被
self.close()
调用

两个重复的id看起来正好相隔30分钟。这只意味着一件事,当连接关闭时,会安排另一个计时器,第二个计时器在超时时打印复制的日志。从您的代码判断,这只可能发生在消息上的

客户端如何处理连接关闭?客户机是否可能在收到FIN后立即向服务器发送消息

在tornado源代码中

# Give the client a few seconds to complete a clean shutdown,
# otherwise just close the connection.
self._waiting = self.stream.io_loop.add_timeout(
      self.stream.io_loop.time() + 5, self._abort)
因此,服务器给客户端5秒钟的时间来终止连接,如果客户端在这5秒钟内向服务器发送消息,则可能会导致问题


这只是我的猜测。

common\u close
被调用两次,但连接只超时一次。在第一个示例中,66919在21:51关闭,因为客户端干净地关闭了连接(通过关闭上的
),然后又在22:21关闭,因为超时。连接对象即使在关闭后仍然存在。连接未打开;只有超时保持活动状态。如果超时处于活动状态,则需要删除关闭时的
(或
公用关闭时的

您还应该在
open()
中启动第一个超时,而不是等待消息上的
),并且
force\u close()
应该将
self.timeout
设置为无


由于close()上的Tornado 4.1
将被self.close()调用,因此您不需要调用common\u close(),close()方法将自动调用common\u close()注意:如果您可以查看打开的连接列表,即使第二次关闭66919,也只有3个连接!!!我也这么认为。但是不,close()方法没有调用common_close(),我不知道为什么。是的,确切地说,close在66919上30分钟前已经被调用,然后它超时并再次尝试关闭(意味着它没有真正关闭)。这就是我不明白的…不,正如你所看到的,它们被称为30分钟装置。而且,如果我不明确地把它放进去,公共的\u close()也不会被force\u close调用。。。我不知道为什么。但是如果它关闭了,实例就不应该再存在了,不是吗?它怎么还能有计时器呢?另外,从日志中我可以看出,在第一次“关闭”期间,没有调用任何
on_message
,因为当发送消息时,我会在输出中打印它(
print“Client%s sent message:%s”%(self.id,message)
),我看不到这一点。不过,谢谢,这很有帮助。它让我思考。谢谢!实际上,在
open()
上启动超时是有意义的。但我不明白,当连接实例不再存在时,超时怎么还能保持活动状态……连接和超时