Both sides (asyncio) - websockets 12.0 documentation

Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Both sides (`asyncio`)

class websockets.legacy.protocol.WebSocketCommonProtocol(*, logger=None, ping_interval=20, ping_timeout=20, close_timeout=10, max_size=2**20, max_queue=2**5, read_limit=2**16, write_limit=2**16)

  WebSocket connection.

  `WebSocketCommonProtocol` provides APIs shared between WebSocket servers and clients. You shouldn’t use it directly. Instead, use `WebSocketClientProtocol` or `WebSocketServerProtocol`.

  This documentation focuses on low-level details that aren’t covered in the documentation of `WebSocketClientProtocol` and `WebSocketServerProtocol` for the sake of simplicity.

  Once the connection is open, a Ping frame is sent every `ping_interval` seconds. This serves as a keepalive. It helps keeping the connection open, especially in the presence of proxies with short timeouts on inactive connections. Set `ping_interval` to `None` to disable this behavior.

  If the corresponding Pong frame isn’t received within `ping_timeout` seconds, the connection is considered unusable and is closed with code 1011. This ensures that the remote endpoint remains responsive. Set `ping_timeout` to `None` to disable this behavior.

  See the discussion of timeouts for details.

  The `close_timeout` parameter defines a maximum wait time for completing the closing handshake and terminating the TCP connection. For legacy reasons, `close()` completes in at most `5 * close_timeout` seconds for clients and `4 * close_timeout` for servers.

  `close_timeout` is a parameter of the protocol because websockets usually calls `close()` implicitly upon exit:

  - on the client side, when using `connect()` as a context manager;

  - on the server side, when the connection handler terminates.

  To apply a timeout to any other API, wrap it in `timeout()` or `wait_for()`.

  The `max_size` parameter enforces the maximum size for incoming messages in bytes. The default value is 1 MiB. If a larger message is received, `recv()` will raise `ConnectionClosedError` and the connection will be closed with code 1009.

  The `max_queue` parameter sets the maximum length of the queue that holds incoming messages. The default value is `32`. Messages are added to an in-memory queue when they’re received; then `recv()` pops from that queue. In order to prevent excessive memory consumption when messages are received faster than they can be processed, the queue must be bounded. If the queue fills up, the protocol stops processing incoming data until `recv()` is called. In this situation, various receive buffers (at least in `asyncio` and in the OS) will fill up, then the TCP receive window will shrink, slowing down transmission to avoid packet loss.

  Since Python can use up to 4 bytes of memory to represent a single character, each connection may use up to `4 * max_size * max_queue` bytes of memory to store incoming messages. By default, this is 128 MiB. You may want to lower the limits, depending on your application’s requirements.

  The `read_limit` argument sets the high-water limit of the buffer for incoming bytes. The low-water limit is half the high-water limit. The default value is 64 KiB, half of asyncio’s default (based on the current implementation of `StreamReader`).

  The `write_limit` argument sets the high-water limit of the buffer for outgoing bytes. The low-water limit is a quarter of the high-water limit. The default value is 64 KiB, equal to asyncio’s default (based on the current implementation of `FlowControlMixin`).

  See the discussion of memory usage for details.

  Parameters:

    - logger (Optional[LoggerLike]) – Logger for this server. It defaults to `logging.getLogger("websockets.protocol")`. See the logging guide for details.

    - ping_interval (Optional[float]) – Delay between keepalive pings in seconds. `None` disables keepalive pings.

    - ping_timeout (Optional[float]) – Timeout for keepalive pings in seconds. `None` disables timeouts.

    - close_timeout (Optional[float]) – Timeout for closing the connection in seconds. For legacy reasons, the actual timeout is 4 or 5 times larger.

    - max_size (Optional[int]) – Maximum size of incoming messages in bytes. `None` disables the limit.

    - max_queue (Optional[int]) – Maximum number of incoming messages in receive buffer. `None` disables the limit.

    - read_limit (int) – High-water mark of read buffer in bytes.

    - write_limit (int) – High-water mark of write buffer in bytes.

  await recv()

    Receive the next message.

    When the connection is closed, `recv()` raises `ConnectionClosed`. Specifically, it raises `ConnectionClosedOK` after a normal connection closure and `ConnectionClosedError` after a protocol error or a network failure. This is how you detect the end of the message stream.

    Canceling `recv()` is safe. There’s no risk of losing the next message. The next invocation of `recv()` will return it.

    This makes it possible to enforce a timeout by wrapping `recv()` in `timeout()` or `wait_for()`.

    Returns:

      A string (`str`) for a Text frame. A bytestring (`bytes`) for a Binary frame.

    Return type:

      Data

    Raises:

      - ConnectionClosed – When the connection is closed.

      - RuntimeError – If two coroutines call `recv()` concurrently.

  await send(message)

    Send a message.

    A string (`str`) is sent as a Text frame. A bytestring or bytes-like object (`bytes`, `bytearray`, or `memoryview`) is sent as a Binary frame.

    `send()` also accepts an iterable or an asynchronous iterable of strings, bytestrings, or bytes-like objects to enable fragmentation. Each item is treated as a message fragment and sent in its own frame. All items must be of the same type, or else `send()` will raise a `TypeError` and the connection will be closed.

    `send()` rejects dict-like objects because this is often an error. (If you want to send the keys of a dict-like object as fragments, call its `keys()` method and pass the result to `send()`.)

    Canceling `send()` is discouraged. Instead, you should close the connection with `close()`. Indeed, there are only two situations where `send()` may yield control to the event loop and then get canceled; in both cases, `close()` has the same effect and is more clear:

    1. The write buffer is full. If you don’t want to wait until enough data is sent, your only alternative is to close the connection. `close()` will likely time out then abort the TCP connection.

    2. `message` is an asynchronous iterator that yields control. Stopping in the middle of a fragmented message will cause a protocol error and the connection will be closed.

    When the connection is closed, `send()` raises `ConnectionClosed`. Specifically, it raises `ConnectionClosedOK` after a normal connection closure and `ConnectionClosedError` after a protocol error or a network failure.

    Parameters:

      message (Union[Data, Iterable[Data], AsyncIterable[Data]) – message to send.

    Raises:

      - ConnectionClosed – When the connection is closed.

      - TypeError – If `message` doesn’t have a supported type.

  await close(code=CloseCode.NORMAL_CLOSURE, reason='')

    Perform the closing handshake.

    `close()` waits for the other end to complete the handshake and for the TCP connection to terminate. As a consequence, there’s no need to await `wait_closed()` after `close()`.

    `close()` is idempotent: it doesn’t do anything once the connection is closed.

    Wrapping `close()` in `create_task()` is safe, given that errors during connection termination aren’t particularly useful.

    Canceling `close()` is discouraged. If it takes too long, you can set a shorter `close_timeout`. If you don’t want to wait, let the Python process exit, then the OS will take care of closing the TCP connection.

    Parameters:

      - code (int) – WebSocket close code.

      - reason (str) – WebSocket close reason.

  await wait_closed()

    Wait until the connection is closed.

    This coroutine is identical to the `closed` attribute, except it can be awaited.

    This can make it easier to detect connection termination, regardless of its cause, in tasks that interact with the WebSocket connection.

  await ping(data=None)

    Send a Ping.

    A ping may serve as a keepalive, as a check that the remote endpoint received all messages up to this point, or to measure `latency`.

    Canceling `ping()` is discouraged. If `ping()` doesn’t return immediately, it means the write buffer is full. If you don’t want to wait, you should close the connection.

    Canceling the `Future` returned by `ping()` has no effect.

    Parameters:

      data (Optional[Data]) – payload of the ping; a string will be encoded to UTF-8; or `None` to generate a payload containing four random bytes.

    Returns:

      A future that will be completed when the corresponding pong is received. You can ignore it if you don’t intend to wait. The result of the future is the latency of the connection in seconds.

          pong_waiter = await ws.ping()
          # only if you want to wait for the corresponding pong
          latency = await pong_waiter

    Return type:

      Future[float]

    Raises:

      - ConnectionClosed – When the connection is closed.

      - RuntimeError – If another ping was sent with the same data and the corresponding pong wasn’t received yet.

  await pong(data=b'')

    Send a Pong.

    An unsolicited pong may serve as a unidirectional heartbeat.

    Canceling `pong()` is discouraged. If `pong()` doesn’t return immediately, it means the write buffer is full. If you don’t want to wait, you should close the connection.

    Parameters:

      data (Data) – Payload of the pong. A string will be encoded to UTF-8.

    Raises:

      ConnectionClosed – When the connection is closed.

  WebSocket connection objects also provide these attributes:

  id: UUID

    Unique identifier of the connection. Useful in logs.

  logger: Logger | LoggerAdapter

    Logger for this connection.

  property local_address: Any

    Local address of the connection.

    For IPv4 connections, this is a `(host, port)` tuple.

    The format of the address depends on the address family; see `getsockname()`.

    `None` if the TCP connection isn’t established yet.

  property remote_address: Any

    Remote address of the connection.

    For IPv4 connections, this is a `(host, port)` tuple.

    The format of the address depends on the address family; see `getpeername()`.

    `None` if the TCP connection isn’t established yet.

  property open: bool

    `True` when the connection is open; `False` otherwise.

    This attribute may be used to detect disconnections. However, this approach is discouraged per the EAFP principle. Instead, you should handle `ConnectionClosed` exceptions.

  property closed: bool

    `True` when the connection is closed; `False` otherwise.

    Be aware that both `open` and `closed` are `False` during the opening and closing sequences.

  latency: float

    Latency of the connection, in seconds.

    This value is updated after sending a ping frame and receiving a matching pong frame. Before the first ping, `latency` is `0`.

    By default, websockets enables a keepalive mechanism that sends ping frames automatically at regular intervals. You can also send ping frames and measure latency with `ping()`.

  The following attributes are available after the opening handshake, once the WebSocket connection is open:

  path: str

    Path of the opening handshake request.

  request_headers: Headers

    Opening handshake request headers.

  response_headers: Headers

    Opening handshake response headers.

  subprotocol: Subprotocol | None

    Subprotocol, if one was negotiated.

  The following attributes are available after the closing handshake, once the WebSocket connection is closed:

  property close_code: int | None

    WebSocket close code, defined in section 7.1.5 of RFC 6455.

    `None` if the connection isn’t closed yet.

  property close_reason: str | None

    WebSocket close reason, defined in section 7.1.6 of RFC 6455.

    `None` if the connection isn’t closed yet.