docs: def connect(self,
                  servers=["nats://127.0.0.1:4222"],
                  loop=None,
                  # 'io_loop' and 'loop' are the same, but we have
                  # both params to be consistent with asyncio client.
                  io_loop=None,
  
                  # Event Callbacks
                  error_cb=None,
                  disconnected_cb=None,
                  reconnected_cb=None,
                  closed_cb=None,
                  # 'close_cb' is the same as 'closed_cb' but we have
                  # both params to be consistent with the asyncio client.
                  close_cb=None,
  
                  # CONNECT options
                  name=None,
                  pedantic=False,
                  verbose=False,
                  no_echo=False,
                  user=None,
                  password=None,
                  token=None,
  
                  # Reconnect logic
                  allow_reconnect=True,
                  connect_timeout=DEFAULT_CONNECT_TIMEOUT,
                  reconnect_time_wait=RECONNECT_TIME_WAIT,
                  max_reconnect_attempts=MAX_RECONNECT_ATTEMPTS,
                  dont_randomize=False,
  
                  # Ping Interval
                  ping_interval=DEFAULT_PING_INTERVAL,
                  max_outstanding_pings=MAX_OUTSTANDING_PINGS,
                  tls=None,
                  max_read_buffer_size=DEFAULT_READ_BUFFER_SIZE,
                  max_write_buffer_size=DEFAULT_WRITE_BUFFER_SIZE,
                  read_chunk_size=DEFAULT_READ_CHUNK_SIZE,
                  tcp_nodelay=False,
                  drain_timeout=DEFAULT_DRAIN_TIMEOUT,
                  ):
          """
          Establishes a connection to a NATS server.
  
          Examples:
  
            # Configure pool of NATS servers.
            nc = nats.io.client.Client()
            yield nc.connect({ 'servers': ['nats://192.168.1.10:4222', 'nats://192.168.2.10:4222'] })
  
            # User and pass are to be passed on the uri to authenticate.
            yield nc.connect({ 'servers': ['nats://hello:world@192.168.1.10:4222'] })
  
            # Simple URL can be used as well.
            yield nc.connect('demo.nats.io:4222')
  
          """
          self._setup_server_pool(servers)
          self._loop = io_loop or loop or tornado.ioloop.IOLoop.current()
          self._error_cb = error_cb
          self._closed_cb = closed_cb or close_cb
          self._reconnected_cb = reconnected_cb
          self._disconnected_cb = disconnected_cb
          self._max_read_buffer_size = max_read_buffer_size
          self._max_write_buffer_size = max_write_buffer_size
          self._read_chunk_size = read_chunk_size
  
          self.options["verbose"] = verbose
          self.options["pedantic"] = pedantic
          self.options["name"] = name
          self.options["no_echo"] = no_echo
          self.options["user"] = user
          self.options["password"] = password
          self.options["token"] = token
          self.options["max_outstanding_pings"] = max_outstanding_pings
          self.options["max_reconnect_attempts"] = max_reconnect_attempts
          self.options["reconnect_time_wait"] = reconnect_time_wait
          self.options["dont_randomize"] = dont_randomize
          self.options["allow_reconnect"] = allow_reconnect
          self.options["tcp_nodelay"] = tcp_nodelay
  
          # In seconds
          self.options["connect_timeout"] = connect_timeout
          self.options["ping_interval"] = ping_interval
          self.options["drain_timeout"] = drain_timeout
  
          # TLS customizations
          if tls is not None:
              self.options["tls"] = tls
  
          while True:
              try:
                  s = self._next_server()
                  if s is None:
                      raise ErrNoServers
  
                  # Check when was the last attempt and back off before reconnecting
                  if s.last_attempt is not None:
                      now = time.time()
                      if (now - s.last_attempt
                          ) < self.options["reconnect_time_wait"]:
                          yield tornado.gen.sleep(
                              self.options["reconnect_time_wait"])
  
                  # Mark that we have attempted to connect
                  s.reconnects += 1
                  s.last_attempt = time.time()
                  yield self._server_connect(s)
                  self._current_server = s
  
                  # Mark that TCP connect worked against this server.
                  s.did_connect = True
  
                  # Established TCP connection at least and about
                  # to send connect command, which might not succeed
                  # in case TLS required and handshake failed.
                  self._status = Client.CONNECTING
                  yield self._process_connect_init()
                  break
              except ErrNoServers:
                  raise
              except Exception as e:
                  self._status = Client.DISCONNECTED
                  self._err = e
                  if self._error_cb is not None:
                      self._error_cb(ErrServerConnect(e))
                  if not self.options["allow_reconnect"]:
                      raise ErrNoServers
  
          # Flush pending data before continuing in connected status.
          # FIXME: Could use future here and wait for an error result
          # to bail earlier in case there are errors in the connection.
          yield self._flush_pending()
  
          # First time connecting to NATS so if there were no errors,
          # we can consider to be connected at this point.
          self._status = Client.CONNECTED
  
          # Prepare the ping pong interval.
          self._ping_timer = tornado.ioloop.PeriodicCallback(
              self._ping_interval, self.options["ping_interval"] * 1000)
          self._ping_timer.start()