websockets Python Library

repository·main·Indexed 26 days ago

https://github.com/python-websockets/websockets

A Python library for building WebSocket servers and clients according to RFC 6455 and 7692. It emphasizes correctness, simplicity, and performance, supporting multiple concurrency models including asyncio and threading. The library includes a CLI interactive client and provides guidance on deployment to platforms like Fly and Heroku, as well as load balancing using HAProxy and Supervisor.

Tokens
47.6K
Snippets
82
Records
303
Agent score
90%

What's inside websockets

  1. Overview of websockets

    main

    websockets is a Python library for building WebSocket servers and clients. It focuses on correctness (RFC 6455 compliance), simplicity, robustness, and performance.

    It provides multiple implementation styles:

    • asyncio API: The default implementation using Python's standard asynchronous I/O framework, providing an elegant coroutine-based API.
    • threading API: A synchronous implementation built on top of threading.
    • Sans-I/O implementation: An implementation that does not perform I/O itself, allowing for integration with custom I/O loops.
  2. Choose a websockets implementation based on your concurrency model

    main

    The websockets library provides multiple implementations tailored to different concurrency requirements and runtime environments:

    • asyncio (Default): The recommended implementation, ideal for servers handling many concurrent clients.
    • trio: An alternative for servers handling many concurrent clients using the Trio async framework.
    • threading: A synchronous implementation suitable for clients where threading is preferred over async/await.
    • Sans-I/O: A low-level layer designed for integration into third-party libraries (like application servers) that manage their own I/O.
    • Legacy: A deprecated historical implementation that will be removed by 2030. Avoid using this for new projects.

    Check the specific feature support and limitations for each implementation in the features documentation.

  3. Understand the opening handshake process

    main

    The opening handshake is performed automatically during connection establishment:

    • Client side: client.connect builds an HTTP Upgrade request, writes it, reads the response, validates extensions/subprotocols, and moves to the OPEN state.
    • Server side: The server reads the HTTP request, optionally calls process_request (a hook to abort the handshake), negotiates extensions/subprotocols, and writes the HTTP response before passing the connection to the ws_handler.

    If the handshake fails, the connection is failed immediately.

  4. Understand the API design: Coroutines vs Callbacks

    main
    The websockets library does not provide onopen, onmessage, onerror, or onclose callback APIs. Instead, it provides high-level, coroutine-based APIs. This design choice is intended to make managing control flow in concurrent code easier compared to traditional callback-based patterns.
  5. Choose a websockets implementation paradigm

    main

    The websockets library provides three distinct implementation paradigms depending on your network I/O and control flow requirements:

    1. asyncio: The default implementation built upon Python's built-in asyncio library. It provides an elegant coroutine-based API and is ideal for servers handling many client connections.
    2. threading: A good alternative for clients if you are unfamiliar with asyncio, or for servers handling a small number of client connections.
    3. Sans-I/O: Designed for integration into third-party libraries (like application servers) and used internally by the library.

    Note that the asyncio implementation was updated in version 13.0. The modern implementation resides in websockets.asyncio, while the historical implementation in websockets.legacy was deprecated in version 14.0 and is scheduled for removal by 2030.

  6. Summary of WebSocket communication patterns

    main

    The following patterns are used for basic WebSocket interaction in this project's tutorial:

    • Python Server Setup: Use asyncio.server.serve to start a server.
    • Receiving in Python: Use await websocket.recv() or iterate with async for message in websocket: to process incoming messages.
    • Sending in Python: Use await websocket.send(data).
    • Browser Connection: Use new WebSocket(url).
    • Sending in Browser: Use websocket.send(data).
    • Receiving in Browser: Listen for the message event via websocket.addEventListener("message", callback).
  7. Understand the WebSocket connection lifecycle (legacy)

    main

    In the websockets.legacy implementation, connections follow a state machine:

    • CONNECTING: Initial state.
    • OPEN: Opening handshake is complete.
    • CLOSING: Closing handshake has started.
    • CLOSED: The TCP connection is closed.

    Transitions to OPEN occur after the opening handshake completes. Transitions to CLOSING occur when a close frame is sent or received. The CLOSED state is reached when the underlying TCP connection is lost.

  8. Scale and load test a websockets deployment

    main

    Scale your websockets deployment using kubectl scale to increase or decrease the number of replicas. To perform load testing, you can use a benchmark script to connect multiple clients in parallel to the service.

    Note: When running high-concurrency benchmarks, ensure you increase your system's open file limit using ulimit -n.

  9. Prepare a websockets app for Koyeb deployment

    main

    To deploy a websockets server to Koyeb, your application must meet specific requirements for a Platform as a Service (PaaS) environment:

    1. Port Configuration: The server must listen on the port provided by the $PORT environment variable.
    2. Health Check: Provide an HTTP endpoint for health checks (e.g., /healthz).
    3. Graceful Shutdown: The application must handle the SIGTERM signal to close connections and exit cleanly.

    You will need to provide a requirements.txt file declaring websockets as a dependency and a Procfile to instruct Koyeb on how to run the application.

  10. Shut down a WebSocketServer gracefully

    main

    To shut down a WebSocketServer asynchronously, use the .close() method. This follows a two-step process:

    1. Stop listening for and accepting new connections.
    2. Close all established connections using close code 1001 (going away). If a connection is still in the middle of an opening handshake, it is closed with HTTP status code 503 (Service Unavailable).

    Calling .close() is idempotent; subsequent calls are ignored. You can use .wait_closed() to wait for the shutdown process to complete.

  11. Handle the WebSocket closing handshake

    main

    The closing handshake ensures a clean termination of the connection:

    • Initiated by remote: When a close frame is received while in the OPEN state, the connection moves to CLOSING, a close frame is sent in response, and read_message (or recv) returns None.
    • Initiated locally: Calling close() moves the state to CLOSING and sends a close frame. The connection waits for the remote side to send its close frame.
    • Timeouts: If the remote side does not send a close frame within the configured close_timeout, the connection is failed. The total handshake duration can take up to 2 * close_timeout.