LimeCoda

    How to build a basic websocket server in Python

    December 30, 2019

    Today I’m going to go through the process of creating a basic websocket server in Python.

    These days users on the internet demand everything in real-time, so being able to use websockets to serve content will become an increasingly desirable skill. With many of today’s software and technology companies making use of them, to give yourself a chance of getting a job with them, it will benefit you to understand how they work.

    Websockets have many use cases, including:

    • Social feeds – don’t wait around to see what your friends just had for dinner.
    • Communication apps – communicate with anyone in real-time.
    • Sports updates – everybody needs to know instantly what’s happening in their favourite game.

    We are going to make use of the following Python modules/libraries in this tutorial:

    • websockets – the most import module in this exercise to create the websocket server that will listen for client connections.
    • asyncio – as the websocket server is I/O bound, this module is also absolutely necessary to keep the server running awaiting input/output.

    Before we get started, REMEMBER, this is not a production ready websocket server so should not be used for any live projects, it is just a basic demonstration!

    With that out the way, let’s get to it…

    As a prerequisite, you must have Python 3 installed on your system to run this project. For the websocket server we’re going to need only one file and we’ll call it server.py.

    Basic websocket server

    server.py

    #!/usr/bin/env python3
    
    import asyncio
    import websockets
    
    async def server(websocket, path):
        # Get received data from websocket
        data = await websocket.recv()
    
        # Send response back to client to acknowledge receiving message
        await websocket.send("Thanks for your message: " + data)
    
    # Create websocket server
    start_server = websockets.serve(server, "localhost", 6789)
    
    # Start and run websocket server forever
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()

    Let’s take a look at what is happening here. Lines 13-18 are the most important lines.

    # Create websocket server
    start_server = websockets.serve(server, "localhost", 6789)

    Here we create a server running on localhost at port 6789 and tell it to run the server function whenever a client connection is established.

    # Start and run websocket server forever
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()

    The above lines make use of the asyncio module to keep the server running, awaiting connections and input.

    async def server(websocket, path):
        # Get received data from websocket
        data = await websocket.recv()
    
        # Send response back to client to acknowledge receiving message
        await websocket.send("Thanks for your message: " + data)

    This is the function that will run whenever a client connection to the websocket server is established. Two arguments will be passed with each connection, the websocket object used to identify the client and the path of the client websocket (defaults to “/” if not specified by the client). This function then waits to receive data from the client and sends back a response thanking the client and repeating the data they sent.

    Running the websocket server

    To get the server running we simply need to open a terminal and ensure that our server.py file is executable, by entering the following (ensuring that we have changed directory to the directory containing the server file):

    chmod +x server.py

    And then typing the following to run the server:

    ./server.py

    This process will lock up the terminal window, so to keep it running I would advise leaving the terminal window open in the background. To stop the server, you can either close the terminal or quit the process (e.g. Ctrl-C).

    Testing the server

    We can test if the server is working multiple ways, for example, using a Python client script or a webpage using the HTML5 websocket API.

    Here I’ve included a Python client script, that we will call client.py. This client will ask a user to enter a username and then will send it to the server and receive a response thanking them for their message and repeating their entered username back to them.

    client.py

    #!/usr/bin/env python3
    
    import asyncio
    import websockets
    import json
    
    async def client():
        uri = "ws://localhost:6789"
        async with websockets.connect(uri) as websocket:
            # Allow user to enter username into command line
            username = input("Enter a username: ")
            data = json.dumps({"username": username})
    
            # Send username as JSON object to server
            await websocket.send(data)
            
            response = await websocket.recv()
            print(response)
            
    asyncio.get_event_loop().run_until_complete(client())

    To run the client in a terminal, like server.py above, make sure that you make the file executable, and enter:

    ./client.py

    Once you have been prompted for a username, entered and hit return, your terminal should resemble something like below:

    $ ./client.py 
    Enter a username: Bill
    Thanks for your message: {"username": "Bill"}

    Conclusion

    That’s it! I have made any code covered in this tutorial available in a python-websocket-server project on GitHub. Remember that this was just a basic demonstration of websockets in Python and that you will need to build on this if you would like to build a production ready websocket server, capable of much more, such as authentication.

    © LimeCoda 2020