Python: Websocket client

The objective of this post is to explain how to create a simple Python websocket client to contact an online test echo server.

 

Introduction

The objective of this post is to explain how to create a simple Python websocket client to contact an online test echo server.

We will use the websockets library, which allows to develop both websocket clients and servers [1].

To install this Python library, the easiest way is by using pip, a Python package installer. Using pip, we simply need to give the following command on the Windows command line (on some older Python installations you may need to navigate to the Scripts folder before being able to send pip commands):

pip install websockets

Note that this library requires a Python version higher or equal than v3.4 [1]. Nonetheless, most of the examples shown in the documentation use the new async await syntax, so my recommendation is that you use Python v3.5 or higher.

The tests shown below were performed on Python v3.6.


The code

We start our code start by importing our previously installed websockets module. Since this library is built on top os Python’s asyncio framework [2], we will need to also import that module as well.

import asyncio
import websockets

Since the code will work asynchronously, we will declare a Python asynchronous function (also called coroutine [3]) where we will write the client code. We do this by including the async keyword before the function declaration [3].

We will call our function test, as can be seen below.

async def test():
# client code

In order to create a websocket client connection, we need to call the connect function from the websockets module [4]. It yields an object of class WebSocketClientProtocol, which we can then use to send and receive websocket messages [4]. You can read more about yielding in this interesting article.

Note however that on Python version 3.5 or greater, the connect method can be used as a asynchronous context manager [4]. If that’s the case, then later we will not need to explicitly close the connection with a call to the close method since the connection is closed when exiting the context [4].

Since I’m on Python 3.6, I’ll take advantage of the asynchronous context manager. If you are on a Python lower version that doesn’t support it, please check here the websockets module client examples for those versions.

So, we will use the following syntax to get the context manager:

async with EXPR as VAR:

Applied to our example, EXPR corresponds to calling the connect method we have already mentioned. This method receives as input the websocket destination endpoint that we want to contact.

To make our tests simpler, as already mentioned in the introductory section, we will use an online testing websocket server that will echo back the content we send it.

async def test():

    async with websockets.connect('ws://demos.kaazing.com/echo') as websocket:
    #Client async code

Now, to send the actual data, we simply call the send coroutine passing as input the string of data that we want to send to the client. We will send a simple “hello” message.

Since this is a coroutine, we will wait it using the await keyword. Note that calling await suspends the execution of the current coroutine (the one where the call is made which is, in our case, the test function) until the awaitable completes and returns the result data [5].

Note that a coroutine is a awaitable [6], which is why we can use the await keyword on the send coroutine.

In particular for the send we don’t need to analyse its result, so we can move on to the rest of the code. You can check the source code for send here.

await websocket.send("hello")

Next, in order to receive the data echoed back by the client, we call the recv coroutine. It receives no arguments and returns a string with the text frame sent by the server (or a bytes object in case it is a binary frame) [7]. In our case, since it will echo what we previously sent, then it will be a string.

We will store the result of waiting this coroutine in a variable and then print it.

response = await websocket.recv()
print(response)

And with this, we finish our client function. Note that now, in order to execute its code, we need to get the asyncio event loop, since async code can only run inside an event loop [8].

Then, on the event loop, we call the run_until_complete method and pass as input our test coroutine, so it is executed. The final source code can be seen below.

import asyncio
import websockets

async def test():

    async with websockets.connect('ws://demos.kaazing.com/echo') as websocket:

        await websocket.send("hello")

        response = await websocket.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(test())


Testing the code

To test the code, simply run the previous script (I’m using IDLE, the IDE that comes with the Python installation for running the code).

You should get an output similar to figure 1, which shows that the output that gets printed to the Python prompt corresponds exactly to the content we have sent to the server, which is then echoed back to the client.

Python websocket client async

Figure 1 – Output of the program.


References

[1] http://websockets.readthedocs.io/en/stable/intro.html

[2] http://websockets.readthedocs.io/en/stable/index.html

[3] http://stackabuse.com/python-async-await-tutorial/

[4] http://websockets.readthedocs.io/en/stable/api.html#websockets.client.connect

[5] https://www.python.org/dev/peps/pep-0492/#await-expression

[6] https://docs.python.org/3/glossary.html#term-awaitable

[7] http://websockets.readthedocs.io/en/stable/api.html#websockets.protocol.WebSocketCommonProtocol.recv

[8] http://cheat.readthedocs.io/en/latest/python/asyncio.html#event-loops

Advertisements
This entry was posted in Python and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s