Using Python to communicate with web socket using JSON

Soz picture Soz · Jun 6, 2016 · Viewed 26.3k times · Source

In order to better understand how websockets are used beyond the basic hello-world, I set myself the task of getting some data from a page using websockets and JSON (because the source code of gitxiv is readily available, I chose to look at http://gitxiv.com/day/2015/12/31).

Connecting to this websocket via Python seems to be straightforward

from websocket import create_connection
import websocket
import pprint

websocket.enableTrace(True)
ws=create_connection("ws://gitxiv.com/sockjs/212/2aczpiim/websocket")
result = ws.recv()
print "Received '%s'" % result
result = ws.recv()
print "Received '%s'" % result

I'm not entirely clear about the variables in the ws:// url, like '212'. Running this code seems to reliably connect (although it is always possible that failing to have the right variables in there causes the server to refuse to cooperate later?)

Now if I watch the communication between Firefox and the gitxiv page, I see that following connection of the websocket the server sends

o
a["{\"server_id\":\"0\"}"]

The above script gets the same response, so it seems that the connection is successfully made.

However, this is where I stumble. The next step in the communication is that my browser sends quite a lot of information to the web service, such as the line:

"["{\"msg\":\"connect\",\"version\":\"1\",\"support\":[\"1\",\"pre2\",\"pre1\"]}"]"

Sending these lines directly using ws.send() results in 'broken framing'. Sending just:

controlstr='{"msg":"connect","version":"1","support":["1","pre2","pre1"]}';
ws.send(controlstr)

results in something being sent that looks like:

send: '\x81\xbd\xef\x17F8\x945+K\x885|\x1a\x8cx(V\x8at2\x1a\xc350]\x9dd/W\x815|\x1a\xde5j\x1a\x9cb6H\x80e2\x1a\xd5Ld\t\xcd;dH\x9drt\x1a\xc356J\x8a&de\x92'

I get a different error:

'a["{\\"msg\\":\\"error\\",\\"reason\\":\\"Bad request\\"}"]'

It seems, therefore, that there is something wrong in the way that I am sending this JSON message to the websocket. Does anybody know what format it expects, and how to achieve it using websocket/websocket-client? Any clarification/suggestions would be most welcome.

The JSON messages I am looking to send are those that Firefox's Websocket developer tool reports: here is a screenshot:

Firefox Web Developer Tool report

Answer

Wayne Werner picture Wayne Werner · Jun 6, 2016

If you look closely at what what's sent through the browser, notice that it's:

["{\"msg\":\"connect\"}"]

This looks an awful lot like an array of JSON strings. Indeed, if you try to replicate it:

ws.send(json.dumps([json.dumps({'msg': 'connect', 'version': '1', 'support': ['1', 'pre2', 'pre1']})]))

You'll see that you get connected. Here's my entire code:

import json
import pprint
import websocket
from websocket import create_connection

websocket.enableTrace(True)
ws = create_connection('ws://gitxiv.com/sockjs/212/2aczpiim/websocket')

result = ws.recv()
print('Result: {}'.format(result))

result = ws.recv()
print('Result: {}'.format(result))

ws.send(json.dumps([json.dumps({'msg': 'connect', 'version': '1', 'support': ['1', 'pre2', 'pre1']})]))
result = ws.recv()
print('Result: {}'.format(result))