Websocket Communication

WebSocket is a protocol for machine-to-machine communication that keeps a TCP connection open for bi-directional passing of information. The websocket is a connection between two computers. The connection can be used to either send or receive information from either computer. The websocket can be configured as a server or client. A websocket server listens for requests and returns a result based on the input. The server can also function as a client by sending information without a specific request.

Install websockets

The websockets package is a Python library for building WebSocket servers and clients.

pip install websockets

There are other programming languages where websocket server and client are written such as JavaScript and PHP. Websocket communication occurs over TCP so that various programming languages can seamlessly communicate. For example, a Python client can call an API running on a server with JavaScript node.js.

Websocket Server

The Python websockets package is build on top of asyncio for asynchronous actions from the server as it listens for client requests. Create a simple WebSocket server and run the Python script to start the API. The API listens for a name and returns a greeting.

import asyncio
import websockets

async def hello(websocket):
    name = await websocket.recv()
    print(f'Server Received: {name}')
    greeting = f'Hello {name}!'

    await websocket.send(greeting)
    print(f'Server Sent: {greeting}')

async def main():
    async with websockets.serve(hello, "localhost", 8765):
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    asyncio.run(main())

Websocket Client

The websockets client sends a name and listens for a return response.

import asyncio
import websockets

async def hello():
    uri = "ws://localhost:8765"
    async with websockets.connect(uri) as websocket:
        name = input("What's your name? ")

        await websocket.send(name)
        print(f'Client sent: {name}')

        greeting = await websocket.recv()
        print(f"Client received: {greeting}")

if __name__ == "__main__":
    asyncio.run(hello())

✅ Activity

Create a buzzer beater program that awaits a spacebar press response from one or more users. Record the time that each of the users responds, display the response time of the user, and notify the first user that they were the fastest response.

  • Websocket server: Set up a websocket server using the websockets library, and define a function that handles incoming messages from clients. This function should check if the incoming message is a valid response action, and if it is, it should record the time at which the response was sent and send a response back to the client indicating whether they were the first to press the spacebar.
import asyncio
import websockets

# create an empty list to store clients
clients = []

# define a function to handle incoming messages from clients
async def handle_message(websocket, path):
    global clients
    global fastest_time
    message = await websocket.recv()
    if message == "buzz":
        response_time = asyncio.get_event_loop().time()
        clients.append([websocket, response_time])
        if len(clients) == 1:
            await websocket.send("First place!")
            fastest_time = response_time
        else:
            t = round(response_time - fastest_time, 2)
            await websocket.send(f"Response time: {t} sec slower.")

# start the websocket server
async def start_server():
    async with websockets.serve(handle_message, "localhost", 8765):
        print('Websockets Server Started')
        await asyncio.Future()

# run the server
asyncio.run(start_server())
  • Websocket client: Set up a websocket client that connects to the server and sends a message when the user presses the spacebar on their keyboard. The client should also display a message indicating whether they were the first to press the button or how long after the first-place response.
import asyncio
import websockets
import keyboard

# start the websocket client
async def start_client():
    async with websockets.connect("ws://localhost:8765") as websocket:
        done = False
        while not done:
            if keyboard.is_pressed("space"):
                await websocket.send("buzz")
                message = await websocket.recv()
                print(message)
                done = True

# run the client
asyncio.run(start_client())

✅ Knowledge Check

1. Which statement about WebSockets is true?

A. WebSockets are used exclusively for sending data from server to client.
Incorrect. WebSockets allow for bi-directional communication, meaning data can be sent from the server to the client and vice versa.
B. WebSockets maintain a continuous open connection for bi-directional communication.
Correct. WebSockets maintain an open connection, enabling both the client and the server to send data at any time.
C. WebSockets can only communicate with servers and clients written in the same programming language.
Incorrect. WebSocket communication occurs over TCP. Different programming languages can communicate seamlessly as long as they support the WebSocket protocol.
D. Every time a client wants to send data via WebSockets, a new connection is established.
Incorrect. WebSockets keep a TCP connection open, allowing for continuous communication without the need to establish a new connection every time data is exchanged.

2. How does a WebSocket differ from traditional HTTP requests?

A. WebSockets are slower than HTTP because they keep the connection open.
Incorrect. While WebSockets keep a connection open, it doesn't mean they are slower. The persistent connection allows for real-time bi-directional communication without the overhead of repeatedly establishing connections.
B. WebSockets are used for downloading large files, while HTTP requests are not.
Incorrect. Both WebSockets and HTTP requests can be used to transfer data of any size. The main difference lies in how the connection is managed.
C. WebSockets support bi-directional communication, whereas traditional HTTP is mainly unidirectional.
Correct. Traditional HTTP communication is predominantly unidirectional: the client requests and the server responds. With WebSockets, both parties can initiate communication.
D. WebSocket communications are not encrypted, while HTTP communications are always encrypted.
Incorrect. WebSocket communications can be encrypted using "wss://" (WebSocket Secure), similar to how HTTPS encrypts HTTP traffic.