Posted by : M yunus Senin, 15 Februari 2016

Websocket is bi-directional communication protocol which emerged recently, with the introduction of HTML5. It enables full-duplex message based communication between client and server. After connection is established, messages can be transmitted, either client or server initiated. This means that you can make a dynamic web page where changes occur in real time. In that way Websockest communication presents a suitable protocol for IoT world where changes are usually asynchronously occuring and number of clients can be very large. Ok, sounds cool but what do I need to develop such web pages? To implement Websocket communication in your app there are some prerequisites on your server that has to be done. Apart from that, clients have to run browsers that support Webosckets. In this article, a simple example which includes Websocket is presented. The example is tested on Raspbian (kernel ver. 3.12.21) and Debian (kernel ver. 2.6.39). In both cases Apache web server was used to deliver html pages to the clients.
 

Server side

First thing to do is to choose webserver implementation with Websocket protocol support. Among different solutions such as Node.js (Socket.IO, WebSocket-Node, ws), Java (Jetty), Ruby (EventMachine), Python (pywebsocket, Tornado), C++ (libwebsockets), .NET (SuperWebSocket) we have decided to pick Tornado, an asynchronous webserver for python which is capable to simultaneously handle more than 10k connections. To install Tornado we recommend to use some package manager like pip or EasyInstall. We used pip, so get it:
sudo apt-get install pip
After successful installation of pip package manager you can execute the following command to install Tornado:
pip install tornado
Alternatively, you can install Tornado manually (see here). Now your system is ready to use Websocketprotocol.
The next step is to write a simple Tornado web server app. Run your favorite text editor (we like nano):
sudo nano ws.py
and write some code:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web

class WSHandler(tornado.websocket.WebSocketHandler):

  def open(self):
    print 'user is connected.\n'

  def on_message(self, message):
    print 'received message: %s\n' %message
    self.write_message(message + ' OK')

  def on_close(self):
    print 'connection closed\n'

application = tornado.web.Application([(r'/ws', WSHandler),])

if __name__ == "__main__":
  http_server = tornado.httpserver.HTTPServer(application)
  http_server.listen(8888)
  tornado.ioloop.IOLoop.instance().start()
As you can see, code consists of four parts:
  • import of necessary modules,
  • Websocket handler class,
  • Initialization of Tornado app – web app configuration (websocket request handler) and
  • Main program – setting up Tornado server, port definition and service start.
In WSHandler class we have defined three event handlers for basic communication:
  • open – occurs when the connection is established,
  • on_message – executed on every incomming message and
  • on_close – handler triggered on the connection close event.
Here we are connecting appropriate event handler (WSHandler) with the URI to listen to (/ws’):
application = tornado.web.Application([(r'/ws', WSHandler),])
In the main, after defining the port number, we will call the start method of the Tornado server:
if __name__ == "__main__":
  http_server = tornado.httpserver.HTTPServer(application)
  http_server.listen(8888)
  tornado.ioloop.IOLoop.instance().start()
You can finally start the server in the background:
python ws.py &
Now, your server is up and running, or more precisely waiting for websocket connection. If you are connecting over SSH, the server will be killed once you exit the session. To avoid that, use nohup command to ignore hang up signal at the end of SSH connection:
nohup python ws.py &
(Note: Make sure that port 8888 is opened on your machine. Additionally, if you are running Tornado on a machine in your local network which is behind the router, you have to make port forwarding for websockets (port 8888). Otherwise this example won't work for clients that connect from outside).

Client app

To implement websocket protocol all you need is s a simple HTML web page with some JavaScript code. Well, we used JQuery to enable websockets on the client side. Body of HTML document has <label> element for connection status text, <textbox> to input text and <button> for sending messages:
<!doctype html>
<html>
<head>
<title>Websockets</title>
<script src="http://code.jquery.com/jquery-2.0.0.js"></script>
</head>
<body>
<h1>Websockets</h1>
<label id="conn_text"></label><br />
<input type="text" id="input_text"/>
<input type="submit" id="button" value="Send" />
<div id="messages_txt" />
Javascript code should be executed after the page loads, i.e. after loading of JQuery script so it will be placed inside anonymous function which is called when document.ready event occurs:
<script>
  $(document).ready(function () {

  //script goes here

});
</script>
</body>
</html>
We will create an instance of WebSocket class to handle all requests for our app:
var ws = new WebSocket("ws://example.com:8888/ws");  //change example.com with your host
We will define three event handlers: onopen, onmessage and onclose and they are invoked respectively: when connection is opened, when new message arrives from server and when the websocket connection is closed. onopen notifies and onclose alerts client about the connection status while onmessage writes message from the server to the client’s web page:
ws.onopen = function(evt) {
  var conn_status = document.getElementById('conn_text');
  conn_status.innerHTML = "Connection status: Connected!"
};

ws.onmessage = function(evt) {
  var newMessage = document.createElement('p');
  newMessage.textContent = "Server: " + evt.data;
  document.getElementById('messages_txt').appendChild(newMessage);
};

ws.onclose = function(evt) {
  alert ("Connection closed");
};
and message sending is performed when user clicks the button:
$("#button").click(function(evt) {
  evt.preventDefault();
  var message = $("#input_text").val();
  ws.send(message);
  var newMessage = document.createElement('p');
  newMessage.textContent = "Client: " + message;
  document.getElementById('messages_txt').appendChild(newMessage);
});
If you save the whole document on your server you are ready to test websockets. Write address of your webpage into the web browser’s address bar and you will be informed if connecting to server was successful with the message inside the web page: “Connection status: Connected!". Similar information, ”Connection closed”, is alerted after closing the connection (for example if you kill ws.py). On every message sent to the server, the server echoes back  that message but with “OK” in the end. You can see every message sent from client or server in your web page:
The whole code of the web page should look like this:
<!doctype html> 
<html>
<head>
<title>Websocket</title>
<script src="http://code.jquery.com/jquery-2.0.0.js"></script>
</head>
<body>
<h1>Websocket</h1>
<label id="conn_text"></label><br />
<input type="text" id="input_text"/>
<input type="submit" id="button" value="Send" /><br />
<div id="messages_txt" />
<script>
  $(document).ready(function () {
    //change example.com with your IP or your host
    var ws = new WebSocket("ws://example.com:8888/ws");
    ws.onopen = function(evt) {
      var conn_status = document.getElementById('conn_text');
      conn_status.innerHTML = "Connection status: Connected!"
    };
    ws.onmessage = function(evt) {
      var newMessage = document.createElement('p');
      newMessage.textContent = "Server: " + evt.data;
      document.getElementById('messages_txt').appendChild(newMessage);
    };
    ws.onclose = function(evt) {
      alert ("Connection closed");
    };
    $("#button").click(function(evt) {
      evt.preventDefault();
      var message = $("#input_text").val();
      ws.send(message);
      var newMessage = document.createElement('p');
      newMessage.textContent = "Client: " + message;
      document.getElementById('messages_txt').appendChild(newMessage);
    });
  });
</script>
</body></html> 
 
 
 
 
source: http://iot-projects.com/index.php?id=websocket-a-simple-example 

{ 3 komentar... read them below or Comment }

  1. Hi nice, tested on Python2 and Tornado 5 work fine also if I call the write_message from a separate thread (I'm collecting the clients in a global array to do that), but fail with Python3 and same Tornado release with error " There is no current event loop in thread '...' ".
    Do you have some advice how to avoid it and get all working also in Pytgon3?
    Thank

    BalasHapus
  2. Here an example of the code to show the trouble;

    import tornado.httpserver
    import tornado.websocket
    import tornado.ioloop
    import tornado.web
    import socket

    import threading
    import time

    clients=[]
    exitGlobalFlag = False

    # ----------------------------------------
    # TORNADO HANDLER
    # ----------------------------------------
    class WSHandler(tornado.websocket.WebSocketHandler):

    def check_origin(self, origin):
    return True

    def open(self):
    global clients

    print("New connection was opened from " + self.request.remote_ip)
    print("Path: " + self.request.path)
    self.write_message("Welcome to my websocket!")

    if self not in clients:
    clients.append(self)

    def on_message(self, message):
    print("Incoming message: "+message)
    self.write_message("["+self.request.remote_ip+"] You said: " + message)
    if (message == "QUIT"):
    exitGlobalFlag = True
    self.stopTornado()

    def onCloseWrapper(self):
    self.close()
    self.on_close()
    print("LOGOUT command received...")

    def on_close(self):
    print("Connection was closed...")
    if self in clients:
    clients.remove(self)

    def stopTornado(self):
    tornado.ioloop.IOLoop.instance().stop()

    # ----------------------------------------
    # Thread
    # ----------------------------------------
    class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
    threading.Thread.__init__(self)
    self.threadID = threadID
    self.name = name
    self.counter = counter

    def run(self):
    print ("Starting " + self.name)
    while not(exitGlobalFlag):
    for client in clients:
    client.write_message("(Thread: " + self.name + ") Say hello!!!") # <-- EXCEPTION NO CURRENT EVENT LOOP
    time.sleep(1)

    # ----------------------------------------
    # MAIN APPLICATION
    # ----------------------------------------
    if __name__ == "__main__":

    # Run the thread
    thread1 = myThread(1, "Thread-1", 1)
    thread1.start()

    # Set the tornado server
    application = tornado.web.Application([(r'/ws', WSHandler),])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)

    myIP = socket.gethostbyname(socket.gethostname())
    print("Websocket Server Started at: " + myIP)
    tornado.ioloop.IOLoop.instance().start()
    #tornado.ioloop.IOLoop.current().start()

    # Exiting from application
    print("Quit application!")

    BalasHapus
  3. Hi,
    after some time I think to have solved:

    https://stackoverflow.com/questions/51291726/tornado-5-0-2-with-python-3-5-3-accessing-tornado-from-separate-thread

    Regards

    BalasHapus

- Copyright © Legendre-electronics - Date A Live - Powered by Blogger - Designed by Johanes Djogan -