Implementing and testing WebSocket server connection timeout

前端 未结 2 1336
旧巷少年郎
旧巷少年郎 2021-01-03 11:00

I am implementing a WebSockets server in Tornado 3.2. The client connecting to the server won\'t be a browser.

For cases in which there is back-and-forth communicat

相关标签:
2条回答
  • 2021-01-03 11:58

    The timeout-handling code in your first example looks correct to me.

    For testing, each test case gets its own IOLoop, but there is only one IOLoop for both the test and anything else it runs, so you must use add_timeout instead of time.sleep() here as well to avoid blocking the server.

    0 讨论(0)
  • 2021-01-03 11:58

    Ey Ben, I know this question was long ago resolved, but I wanted to share with any user reading this the solution I made for this. It's basically based on yours, but it solves the problem from an external Service that can be easily integrated within any websocket using composition instead of inheritance:

    class TimeoutWebSocketService():
        _default_timeout_delta_ms = 10 * 60 * 1000  # 10 min
    
        def __init__(self, websocket, ioloop=None, timeout=None):
            # Timeout
            self.ioloop = ioloop or tornado.ioloop.IOLoop.current()
            self.websocket = websocket
            self._timeout = None
            self._timeout_delta_ms = timeout or TimeoutWebSocketService._default_timeout_delta_ms
    
        def _close_on_timeout(self):
            self._timeout = None
            if self.websocket.ws_connection:
                self.websocket.close()
    
        def refresh_timeout(self, timeout=None):
            timeout = timeout or self._timeout_delta_ms
            if timeout > 0:
                # Clean last timeout, if one exists
                self.clean_timeout()
    
                # Add a new timeout (must be None from clean).
                self._timeout = self.ioloop.add_timeout(
                    datetime.timedelta(milliseconds=timeout), self._close_on_timeout)
    
        def clean_timeout(self):
            if self._timeout is not None:
                # Remove previous timeout, if one exists.
                self.ioloop.remove_timeout(self._timeout)
                self._timeout = None
    

    In order to use the service, itś as easy as create a new TimeoutWebService instance (optionally with the timeout in ms, as well as the ioloop where it should be executed) and call the method ''refresh_timeout'' to either set the timeout for the first time or reset an already existing timeout, or ''clean_timeout'' to stop the timeout service.

    class BaseWebSocketHandler(WebSocketHandler):
        def prepare(self):
            self.timeout_service = TimeoutWebSocketService(timeout=(1000*60))
    
            ## Optionally starts the service here 
            self.timeout_service.refresh_timeout()
    
            ## rest of prepare method 
    
        def on_message(self):
            self.timeout_service.refresh_timeout()
    
        def on_close(self):
            self.timeout_service.clean_timeout()
    

    Thanks to this approach, you can control when exactly and under which conditions you want to restart the timeout which might differ from app to app. As an example you might only want to refresh the timeout if user acomplish X conditions, or if the message is the expected one.

    I hope ppl enjoy this solution !

    0 讨论(0)
自定义标题
段落格式
字体
字号
代码语言
提交回复
热议问题