Python Tornado Websocket Connections在关闭后仍然打开

时间:2015-07-15 08:08:51

标签: python websocket tornado

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

这里是代码的基本部分(从这里获得帮助后实现:How to automatically close connection serverside after a certain time in Tornado Websocket):

打开连接:

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_close被调用。但似乎即使在被调用之后,从clients删除连接,连接仍然是开放且活动的。

以下是该程序的示例输出:

New connection. ID: 66919
Total number of open connections: 3
2015-07-14 21:51:48.387892
New connection. ID: 12012
Total number of open connections: 4
2015-07-14 21:51:48.641603
Open connections are:
[66919, 12012, 11281, 97458]
Closing connection 66919.
Total time online:
0:00:00.404316
Time between connection start and last message received:
0:00:00
Number of open connections: 3
Open connections are:
[12012, 11281, 97458]
... ...
Number of open connections: 4
Open connections are:
[66246, 12012, 97458, 6069]
2015-07-14 22:21:47.906129
Connection 97458 timed out, server is dropping the connection.
2015-07-14 22:21:47.906167
Open connections are:
[66246, 12012, 97458, 6069]
Closing connection 97458.
Total time online:
0:30:00.000450
Time between connection start and last message received:
0:00:00
Number of open connections: 3
Open connections are:
[66246, 12012, 6069]
2015-07-14 22:21:48.237407
Connection 66919 timed out, server is dropping the connection.
2015-07-14 22:21:48.237444
Open connections are:
[66246, 12012, 6069]
Closing connection 66919.
Total time online:
0:30:00.000143
Time between connection start and last message received:
0:00:00
Number of open connections: 3

可以看出,66919已关闭"间隔30分钟两次。有什么想法吗?

当假设没有更多的开放连接(再次关闭两次,间隔30分钟)时,连接3358被关闭的另一个例子:

Open connections are:
[7046, 16287]
2015-07-15 11:01:13.604125
New connection. ID: 3358
Total number of open connections: 3
2015-07-15 11:01:28.429574
Open connections are:
[7046, 3358, 16287]
Closing connection 3358.
Total time online:
0:00:14.825568
Time between connection start and last message received:
0:00:00
Number of open connections: 2
Open connections are:
[7046, 16287]
--
Open connections are:
[]
2015-07-15 11:31:13.629530
Connection 3358 timed out, server is dropping the connection.
2015-07-15 11:31:13.629586
Open connections are:
[]
Closing connection 3358.
Total time online:
0:30:00.025556
Time between connection start and last message received:
0:00:00
Number of open connections: 0
Open connections are:
[]

有些人指出我不应该在common_close中致电force_close,因为on_close会调用self.close(),但on_close()不会#39;被self.close()调用。

2 个答案:

答案 0 :(得分:3)

common_close被调用两次但连接只超时一次。在您的第一个示例中,66919在21:51关闭,因为客户端干净地关闭了连接(通过on_close),然后由于超时再次在22:21关闭。连接对象即使在关闭后也会继续存在。连接未打开;只有超时仍然有效。如果它处于活动状态,您需要删除on_close(或common_close)中的超时。

您还应该在open()开始第一次超时,而不是等待on_message(),而force_close()应该将self.timeout设置为无。

由于Tornado 4.1 on_close()将由self.close()调用。

答案 1 :(得分:1)

看起来两个重复的ID恰好相隔30分钟。这只能意味着一件事,当连接关闭时,另一个计时器被调度,第二个计时器在超时时打印复制的日志。从您的代码判断,这可能只发生在on_message

您的客户端如何处理连接关闭?客户端收到FIN后会立即向服务器发送消息吗?

在龙卷风源代码中,

# 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秒内向服务器发送消息,则可能会导致问题。

这只是我的猜测。