Run the SocketIO web server.

        :param app: The Flask application instance.
        :param host: The hostname or IP address for the server to listen on.
                     Defaults to 127.0.0.1.
        :param port: The port number for the server to listen on. Defaults to
                     5000.
        :param debug: ``True`` to start the server in debug mode, ``False`` to
                      start in normal mode.
        :param use_reloader: ``True`` to enable the Flask reloader, ``False``
                             to disable it.
        :param extra_files: A list of additional files that the Flask
                            reloader should watch. Defaults to ``None``
        :param log_output: If ``True``, the server logs all incomming
                           connections. If ``False`` logging is disabled.
                           Defaults to ``True`` in debug mode, ``False``
                           in normal mode. Unused when the threading async
                           mode is used.
        :param kwargs: Additional web server options. The web server options
                       are specific to the server used in each of the supported
                       async modes. Note that options provided here will
                       not be seen when using an external web server such
                       as gunicorn, since this method is not called in that
                       case.

def run(self, app, host=None, port=None, **kwargs):
        """Run the SocketIO web server.

        :param app: The Flask application instance.
        :param host: The hostname or IP address for the server to listen on.
                     Defaults to 127.0.0.1.
        :param port: The port number for the server to listen on. Defaults to
                     5000.
        :param debug: ``True`` to start the server in debug mode, ``False`` to
                      start in normal mode.
        :param use_reloader: ``True`` to enable the Flask reloader, ``False``
                             to disable it.
        :param extra_files: A list of additional files that the Flask
                            reloader should watch. Defaults to ``None``
        :param log_output: If ``True``, the server logs all incomming
                           connections. If ``False`` logging is disabled.
                           Defaults to ``True`` in debug mode, ``False``
                           in normal mode. Unused when the threading async
                           mode is used.
        :param kwargs: Additional web server options. The web server options
                       are specific to the server used in each of the supported
                       async modes. Note that options provided here will
                       not be seen when using an external web server such
                       as gunicorn, since this method is not called in that
                       case.
        """
        if host is None:
            host = '127.0.0.1'
        if port is None:
            server_name = app.config['SERVER_NAME']
            if server_name and ':' in server_name:
                port = int(server_name.rsplit(':', 1)[1])
            else:
                port = 5000

        debug = kwargs.pop('debug', app.debug)
        log_output = kwargs.pop('log_output', debug)
        use_reloader = kwargs.pop('use_reloader', debug)
        extra_files = kwargs.pop('extra_files', None)

        app.debug = debug
        if app.debug and self.server.eio.async_mode != 'threading':
            # put the debug middleware between the SocketIO middleware
            # and the Flask application instance
            #
            #    mw1   mw2   mw3   Flask app
            #     o ---- o ---- o ---- o
            #    /
            #   o Flask-SocketIO
            #    \  middleware
            #     o
            #  Flask-SocketIO WebSocket handler
            #
            # BECOMES
            #
            #  dbg-mw   mw1   mw2   mw3   Flask app
            #     o ---- o ---- o ---- o ---- o
            #    /
            #   o Flask-SocketIO
            #    \  middleware
            #     o
            #  Flask-SocketIO WebSocket handler
            #
            self.sockio_mw.wsgi_app = DebuggedApplication(self.sockio_mw.wsgi_app,
                                                          evalex=True)

        if self.server.eio.async_mode == 'threading':
            from werkzeug._internal import _log
            _log('warning', 'WebSocket transport not available. Install '
                            'eventlet or gevent and gevent-websocket for '
                            'improved performance.')
            app.run(host=host, port=port, threaded=True,
                    use_reloader=use_reloader, **kwargs)
        elif self.server.eio.async_mode == 'eventlet':
            def run_server():
                import eventlet
                import eventlet.wsgi
                import eventlet.green
                addresses = eventlet.green.socket.getaddrinfo(host, port)
                if not addresses:
                    raise RuntimeError('Could not resolve host to a valid address')
                eventlet_socket = eventlet.listen(addresses[0][4], addresses[0][0])

                # If provided an SSL argument, use an SSL socket
                ssl_args = ['keyfile', 'certfile', 'server_side', 'cert_reqs',
                            'ssl_version', 'ca_certs',
                            'do_handshake_on_connect', 'suppress_ragged_eofs',
                            'ciphers']
                ssl_params = {k: kwargs[k] for k in kwargs if k in ssl_args}
                if len(ssl_params) > 0:
                    for k in ssl_params:
                        kwargs.pop(k)
                    ssl_params['server_side'] = True  # Listening requires true
                    eventlet_socket = eventlet.wrap_ssl(eventlet_socket,
                                                        **ssl_params)

                eventlet.wsgi.server(eventlet_socket, app,
                                     log_output=log_output, **kwargs)

            if use_reloader:
                run_with_reloader(run_server, extra_files=extra_files)
            else:
                run_server()
        elif self.server.eio.async_mode == 'gevent':
            from gevent import pywsgi
            try:
                from geventwebsocket.handler import WebSocketHandler
                websocket = True
            except ImportError:
                websocket = False

            log = 'default'
            if not log_output:
                log = None
            if websocket:
                self.wsgi_server = pywsgi.WSGIServer(
                    (host, port), app, handler_class=WebSocketHandler,
                    log=log, **kwargs)
            else:
                self.wsgi_server = pywsgi.WSGIServer((host, port), app,
                                                     log=log, **kwargs)

            if use_reloader:
                # monkey patching is required by the reloader
                from gevent import monkey
                monkey.patch_all()

                def run_server():
                    self.wsgi_server.serve_forever()

                run_with_reloader(run_server, extra_files=extra_files)
            else:
                self.wsgi_server.serve_forever()