Skip to content
Yihong Luo edited this page Aug 21, 2015 · 8 revisions

#What are WebSockets WebSockets defines a bi-directional web communication that makes it possible to open an interactive session between the server and the client’s browser. The server and the client can both send messages and receive event-driven responses. Instead of polling the server for an update, the server can push notifications whenever there is an update in the system.

#How does it work

##Client Side The connection to server can be established by creating a WebSocket object which has different functions. Once a message containing information about the status, the name and the UUID of the updated model, it will call the corresponding function to fetch the specific resource.

###1. Handshake The server has first to listen for incoming messages using standard TCP socket and the handshake is the connection from HTTP to WS. Once the connection is established, the server and the client can communicate through socket message. The connection can be opened on the client side using
var ws = new WebSocket('ws://' + location.host + '/ws/rodan?subscribe-broadcast&publish-broadcast&echo'); ####Status code Each WebSocket object has a property .readyState that defines the status of the object
-0 Connecting
-1 Opened
-2 Closing
-3 Closed
The connection is ready to communicate only when the status code equals to 1.

####ws.onopen
Executes codes as soon as WebSocket is connected and can be used to set interval for heartbeats.

    ws.onopen = function on_open() {
        console.log("Websocket connected");
    }

###2. Exchange Data The WebSocket object has different functions including .open, .onmessage, .onerror, and .onclose. In order to receive messages, the function .onmessage is used.
####Receiving messages with ws.onmessage Executes codes when a socket message is received and can be used to check if any heartbeat messages are missed.

    ws.onmessage = function on_message(e) {
        if (e.data === heartbeat_msg) {
            missed_heartbeats = 0;
            return;
        }
        console.log("Received: " + e.data);
    }

####Sending messages with ws.send
ws.send("message_string")

###3. Heartbeats After the handshake, the server will send a ping to the client and the client replies with a pong. A ping or pong is a control frame in order to check if the client is still connected. If too many heartbeats are missed, the connection will close automatically. The heartbeat configuration is in settings.py file, where the heartbeat message can be customized.
WS4REDIS_HEARTBEAT = '--heartbeat--'

###4. Error Display The WebSocket object has an EventListener for any encountered error.
####ws.onerror Displays any error with the WebSockets.

    ws.onerror = function on_error(e) {
        console.error(e);
    }

###5. Close connection The connection can be closed when the client or the server sends a control frame such as the heartbeats with data containing a specified control sequence to begin the closing handshake.

####ws.onclose Executes codes when the connection is closed and can be used to check if the closing event was clean.

    ws.onclose = function on_close(e) {
        if (e.wasClean) {
            console.log("Connection was closed properly");
        } else {
            console.log ("Connection not properly closed");
        }
        console.log("Code: " + e.code + "Reason: " + e.reason);
    }

##Server Side ###Dependencies and installation ####Redis Redis is a flexible, open-source, key value data store. It allows the user to store vast amounts of data without the limits of a relational database. Redis is used as a message queue and is run side by side with Django.
To install Redis, download the package from here:

wget http://download.redis.io/redis-stable.tar.gz   
tar xvzf redis-stable.tar.gz  
cd redis-stable   
make

To start Redis server, go into the Redis directory and do:
$> src/redis-server
Once the server is started, you can test it by starting the program redis-cli which can be used to send messages to Redis. When sending a PING command, the server will answer with a PONG if it is working properly.

$> redis-cli   
redis 127.0.0.1:6379> PING      
redis 127.0.0.1:6379> PONG

####ws4redis Websocket for Redis (ws4redis) allows uni- and bidirectional communication from the client to the server and vice versa. Each websocket is identified by the part of the URL which follows the prefix /ws/. Use different uniform locators to distinguish between unrelated communication channels.
To install, first make sure that Redis server is running, then do:
pip install django-websocket-redis
To add heartbeat configuration, a setting should be added WS4REDIS_HEARTBEAT = '--heartbeat--' .

####Psycopg Psycopg is a PostgreSQL adapter for the Python programming language. It is a wrapper for the libpq, the official PostgreSQL client library. And Psycopg2 package is the mature implementation of the adapter.
If it is not already installed, install the package with:
$> pip install psycopg2

###Post-update trigger in Postgres database Instead of the server polling for any update request from the client, the update notification is 'pushed' from the server side by adding triggers inside Postgres tables containing Rodan models. A signal is sent each time an INSERT or UPDATE action is performed on a table containing the trigger. Specifically, looping through the Rodan model tables, the triggers are first destroyed if they already exist, and then they are re-created.
See this file.

###Publish Redis socket messages Every time a signal is received from the post-update trigger, a message containing information about the status of update, the model name and the UUID of the model instance is broadcasted to all subscribed clients through Redis. Redis connection can be opened with:
r = redis.StrictRedis(REDIS_HOST, REDIS_PORT, DB)
where REDIS_HOST, REDIS_PORT, and DB are specified in the settings_production.py.
Once the connection is opened, messages can be broadcasted.
r.publish('rodan:broadcast:rodan', 'message_string')

###Post-migrate signal The process of creating triggers on database tables is performed after receiving the post-migrate signal from Django, ie. triggers will be destroyed and re-created each time this command is executed:
(rodan-env)$> python manage.py migrate

#Stress Testing ##Dependancies and installation Thor is needed for stress testing. Make sure that Node.js is installed on your system. Then, install the module using
$> npm install -g thor

##Testing Then, stress tests can be run by running
$> ~/Rodan/rodan/test/test_load.sh -a[options] -n[options] -s[options]
Running the command will diplay a help menu.
$> ~/Rodan/rodan/test/test_load.sh -h

Options:
-a            Number of connections to test on, if unspecified, 10000 connections will be tested
-n            Number of messages to be sent per connection
-s            Name of the server, eg. rodan.simssa.ca. if unspecified, server will be localhost
-h            Show help instructions    

The test results will be stored in the directory ~/Rodan/rodan/test/test_log.

Clone this wiki locally