code: def close(self, status=STATUS_NORMAL, reason=six.b(""), timeout=3):
          
          if self.connected:
              if status < 0 or status >= ABNF.LENGTH_16:
                  raise ValueError("code is invalid range")
  
              try:
                  self.connected = False
                  self.send(struct.pack('!H', status) +
                            reason, ABNF.OPCODE_CLOSE)
                  sock_timeout = self.sock.gettimeout()
                  self.sock.settimeout(timeout)
                  start_time = time.time()
                  while timeout is None or time.time() - start_time < timeout:
                      try:
                          frame = self.recv_frame()
                          if frame.opcode != ABNF.OPCODE_CLOSE:
                              continue
                          if isEnabledForError():
                              recv_status = struct.unpack("!H", frame.data[0:2])[0]
                              if recv_status != STATUS_NORMAL:
                                  error("close status: " + repr(recv_status))
                          break
                      except:
                          break
                  self.sock.settimeout(sock_timeout)
                  self.sock.shutdown(socket.SHUT_RDWR)
              except:
                  pass
  
              self.shutdown()
docs: Close Websocket object
  
          status: status code to send. see STATUS_XXX.
  
          reason: the reason to close. This must be string.
  
          timeout: timeout until receive a close frame.
              If None, it will wait forever until receive a close frame.