Python websocket client: sending binary content

In this tutorial we will check how to send data in binary frames from a Python websocket client.

Introduction

In this tutorial we will check how to send data in binary frames from a Python websocket client.

We will only develop the client and we will send the messages to this echo server, which should return back to the client the message in the same format it received. We will use the following endpoint:

ws://demos.kaazing.com/echo

So, in our Python program, we will analise the received frame echoed by the server and check if it has the expected binary format. We can do this by looking into the opcode of the frame, which is different depending if it is a binary or a textual frame [1].

For comparison, after the binary content, we will also send some textual content and take a look at the opcode of the received frame, to confirm its type.

We will use this python module for the websocket related functionality. It can be installed via pip with the following command:

pip install websocket-client

This tutorial was tested on Python version 2.7.8.

The code

We will start our code by importing the websocket module, which will expose the functionality we need to connect to the server.

import websocket

After this, we will instantiate an object of class WebSocket, which we will use to connect to the server, send and receive the websocket messages. We will pass no arguments to the constructor.

ws = websocket.WebSocket()

Now that we have our WebSocket object, we will take care of establishing a connection to the remote websocket server. To do so, we simply need to call the connect method on the WebSocket object, passing as input the server endpoint as a string.

ws.connect("ws://demos.kaazing.com/echo")

From this point onward, we should now be able to send data to the server. So, to send data in binary format, we simply need to call the send_binary method of the WebSocket object.

Note that although this method also accepts a string as input and converts it to bytes under the hood, we are going to pass as input an array with the actual value of the bytes we want to send.

We can pass a simple array of integer values as long as we respect the range of values a byte can represent (it should be between 0 and 255). We will send some arbitrary values.

ws.send_binary([100, 220, 130])

Now we can call the recv_frame method on our WebSocket object to receive the frame from the server with the response. Recall that we are reaching an echo server, so it will always return back to us the content we have sent.

This method call will return as output an object of class ABNF, which represents the frame returned by the server.

Note that in a normal use case we don’t deal with the ABNF frame since we can simply obtain the data of the response frame by calling the recv method rather than the recv_frame method.

Nonetheless, in this case, we will check the opcode of the frame to confirm if we are receiving a textual or binary answer, which is why we are using this lower level class.

binAnswer = ws.recv_frame()

Now that we have the frame, we can check the value of the opcode by accessing the opcode attribute of our ABNF object.

Note however that this opcode attribute is an integer representing the value of the opcode for a binary frame, which corresponds to the value 2 [1].

So, the ABNF class has a static dictionary variable called OPCODE_MAP which maps the opcode values to user friendly strings. We will use this dictionary to map our opcode to a readable string and print the result.

print websocket.ABNF.OPCODE_MAP[binAnswer.opcode]

Now that we have printed the opcode, we will also print the data returned back to us. We can do it by accessing the data attribute of our ABNF object.

One important thing to mention is that, even though the response from the server should also be in binary format, this attribute will be of type string. So, we will convert it to a byte array and iterate by all the bytes of the array, printing their value.

Note that the comma after the argument of the print function is a trick to avoid inserting a newline at the end of each print, in order for us to get all the bytes printed in the same line.

for byte in bytearray(binAnswer.data):
    print byte,

After this, we will perform the same test, but now sending content in textual format to the server. To do it, we use the send method on our WebSocket object, passing as input a string with the content.

ws.send("Hello world")

After that, we will again obtain the frame by calling the recv_frame method and then prints its opcode, which should now have the value 1 [1]. Nonetheless, we will again leverage the OPCODE_MAP dictionary to obtain a user friendly string.

This time, we can directly print the received content from the data attribute since it has textual format.

txtAnswer = ws.recv_frame()

print websocket.ABNF.OPCODE_MAP[txtAnswer.opcode]
print txtAnswer.data

To finalize, we need to call the close method on our WebSocket object, so the connection to the server is closed.

ws.close()

The final code can be seen below. It contains some extra prints for better readability.

import websocket

ws = websocket.WebSocket()
ws.connect("ws://demos.kaazing.com/echo")

ws.send_binary([100, 220, 130])
binAnswer = ws.recv_frame()

print "----BINARY---"
print websocket.ABNF.OPCODE_MAP[binAnswer.opcode]

for byte in bytearray(binAnswer.data):
    print byte,

ws.send("Hello world")
txtAnswer = ws.recv_frame()

print "\n----TEXT---"
print websocket.ABNF.OPCODE_MAP[txtAnswer.opcode]
print txtAnswer.data

ws.close()

Testing the code

To test the code, simply run it in the tool of your choice. I’ll be using IDLE, a python IDE.

You should get an output similar to figure 1. As can be seen, for the first case, the frame that is returned back by the server has a binary format, which makes sense since it echoes back what we have sent and we have used a binary format.

In the second case, the opcode is textual, since we have sent textual content to the server and it also echoed the content back.

Sending binary and textual data to a websocket echo server, using Python

Figure 1 – Output of the program.

References

[1] https://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-09.html#rfc.section.11.14

Advertisements

One Reply to “Python websocket client: sending binary content”

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 )

Connecting to %s