Mengenal Websocket dengan Tornado Web Server

Ridwan Fajar 21 Juni 2016

Mengenal Websocket dengan Tornado Web Server

Pernahkah Anda terpikirkan untuk membuat sebuah sistem notifikasi di halaman web Anda? atau membuat sebuah grafik yang dapat berubah setiap menerima perubahan data transaksi layaknya di sebuah display bursa saham. Mungkin Anda juga ingin membuat sebuah aplikasi chat tanpa menggunakan AJAX dan mengendalikan sebuah device melalui WIFI secara realtime. Sejak lahirnya Websocket di HTML5 hal - hal tersebut sudah mulai diteliti dan dikembangkan dan banyak diantara orang - orang yang ngulik pada masalah tersebut telah berhasil mengerjakan sebuah produk dengan memanfaatkan Websocket.

Websocket sendiri adalah sebuah mekanisme dimana client dan server dapat membuka sebuah channel dan dapat saling mengirimi pesan. Berbeda dengan HTTP request yang dilakukan oleh client lalu server dapat memberikan response. Di websocket, server pun dapat lebih dulu memberikan response tanpa menunggu request dari client. Websocket sendiri sudah digunakan di beberapa hal berikut ini:

  • development environment, digunakan untuk memunculkan preview sebuah aplikasi hybrid untuk mobile di web browser ataupun emulator. Anda dapat menemukan hal tersebut bila sedang menggunakan Ionic atau Intel XDK.
  • internet of things, digunakan untuk mengakses device melalui jaringan nirkabel dan mengoperasikan device tersebut secara realtime. Anda dapat menemukan hal tersebut bila Anda pernah mencoba WeIO (menggunakan Tornado Web Server) atau IGN IoT (menggunakan Node.js).
  • realtime chart
  • collaborative text editor
  • collaborative draw application
  • web database, seperti Firebase
  • dan lainnya
Umumnya untuk membangun sebuah websocket server, Node.js lebih populer karena memiliki sebuah library yang bernama Socket.IO. Library tersebut memiliki kode untuk sisi server dan client. Tapi kali ini kita akan membuat websocket server sederhana dengan menggunakan Tornado Web Server dan kode websocket bawaan web browser yang tentunya tidak selengkap Socket.IO. Tornado Web Server sendiri adalah sebuah library yang memiliki web framework, http web server, websocket server, asynchronous programming, dan networking yang ditulis dalam bahasa pemrograman Python. Di tutorial ini Anda hanya membutuhkan:
  • Python
  • Tornado
  • Teks Editor
  • jQUery
  • Beberapa web browser seperti Chrome, Opera, dan Firefox.

Menggunakan HTTP Web Server di Tornado

Untuk menggunakan Tornado, pastikan Anda sudah memasang Python dan PIP di komputer Anda. PIP sendiri adalah sebuah library management yang dimiliki Python. Anda dapat memasang library dan memperbaharuinya secara mudah. Sekarang mari kita gunakan PIP untuk memasang Tornado:
$ pip install tornado
Berikutnya silahkan buat sebuah folder bernama helloworld di direktori yang Anda sukai. Kemudian buatlah dua buah file yaitu index.html dan server.py di dalam folder tersebut:
$ mkdir helloworld
$ cd helloworld
$ touch index.html
$ touch server.py
$ ls helloworld
index.html   server.py
Sebelum melangkah ke websocket server, Anda harus mengetahui terlebih dahulu bagaimana menggunakan sebuah http web server di Tornado. Mari kita buat kode berikut di server.py:
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html")

if name == "main": application = tornado.web.Application([ (r"/", MainHandler), ])

application.listen(8888)
tornado.ioloop.IOLoop.current().start()

Pertama kita meng-import dua buah modul yaitu tornado.ioloop dan tornado.web. Kemudian kita buat sebuah class yang diturunkan dari tornado.web.RequestHandler. RequestHandler adalah sebuah class yang akan menangani HTTP request yang datang dari client kepada Tornado. Di dalamnya kita hanya menggunakan method get untuk menangani HTTP request dengan metode GET (seperti yang Anda ketahui, metode HTTP request secara umum ada GET, POST, PUT, PATCH, DELETE, HEAD, dan OPTIONS). Kemudian di dalam method get() tersebut kita tampilkan halaman HTML yang ada di file index.html dengan menggunakan method render().

Kemudian dibawahnya, kita buat sebuah objek Tornado yang memiliki handler untuk URL root yang ditangani oleh MainHandler. Sehingga ketika client melakukan request terhadap URL root dengan metode GET. Maka method get() di class MainHandler akan dieksekusi. Kemudian setelah membuat objek Tornado, kita jalankan Tornado di port 888 dengan menggunakan method listen. Kemudian kita gas Tornado dengan menggunakan IOloop.current().start().

Saat ini bila dijalankan Anda tidak akan dapat melihat halaman HTML yang dimaksud, jadi mari melangkah ke bagian tutorial berikutnya :D.

Membuat halaman index.html

Sekarang mari kita lengkapi quest pertama kita untuk menampilkan halaman HTML di Tornado. Mari kita buat kode HTML berikut di index.html:
<!DOCTYPE html>
<html>
    <head>
        <title>Demo Websocket menggunakan Tornado!</title>
    </head>
    <body>
        <h1>Demo Websocket menggunakan Tornado!</h1>
        <p>Selamat datang di demo Websocket...</p>
    </body>
</html>
Pada kode diatas kita membuat elemen h1 dan p yang akan memperlihatkan sebuah teks. Sekarang mari kita jalankan Tornado melalui console seperti berikut:
$ python server.py
Berikut adalah screenshot dari kode diatas ketika diakses melalui web browser:

[caption id="attachment_10546" align="alignnone" width="700"]Contoh halaman HTML yang ditampilkan oleh HTTP Server Tornado Contoh halaman HTML yang ditampilkan oleh HTTP Server Tornado[/caption]

Udah gak sabar ingin mencoba websocket-nya kan? sekarang mari kita pindah ke bagian tutorial selanjutnya :D.

Menggunakan Websocket Server di Tornado

Sekarang mari kita perbaharui kode di file server.py. Mari kita import modul tambahan untuk mendukung websocket server sederhana yang akan kita buat. Silahkan tambahkan kode berikut di bagian atas file setelah kode import lainnya:
import tornado.websocket
import uuid
Untuk menggunakan websocket server di Tornado, Anda perlu meng-import tornado.websocket. Kemudian pada kode diatas kita meng-import sebuah modul yang bernama uuid. Modul uuid akan digunakan untuk menghasilkan sebuah universally unique id yang dapat dimanfaatkan untuk membuat sebuah id ketika ada client yang terhubung ke websocket server. Berikutnya mari kita tambahkan class untuk menangani websocket. Tambahkan kode berikut di server.py setelah kode class MainHandler:
...................................................

clients = {} class EchoWSHandler(tornado.websocket.WebSocketHandler): def open(self): print("WebSocket dibuka") self.id = uuid.uuid4() self.stream.set_nodelay(True) clients[self.id] = {"id": self.id, "object": self}

def on_message(self, message):
    self.write_message("Kamu bilang: " + message)
    for client in clients:
        print clients[client]
        target = clients[client]
        target['object'].write_message( str(self.id) + ": " + message)

def on_close(self):
    print("WebSocket ditutup")

...................................................

pada kode diatas, kita membuat sebuah dictionary bernama clients yang akan digunakan untuk menampung client yang terhubung ke websocket server. Client yang dimaksud bukanlah seseorang yang login, tapi sebuah bagian dari halaman web yang terhubung ke websocket server. Dapat terjadi kemungkinan apabila seorang user membuka sebuah tab di Firefox sebanyak tiga tab padahal yang dibuka adalah halaman yang sama atau mirip, kemudian dia membuka juga dua tab di Chrome yang menampilkan halaman serupa. Sehingga terhubunglah lima client padahal yang menggunakannya hanya satu user.

Lalu kita buat sebuah class dengan nama EchoWSHandler yang diturunkan dari tornado.websocket.WebSocketHandler. Lalu kita membuat sebuah method dengan nama open yang akan dijalankan ketika ada sebuah client terhubung ke websocket server. Di dalam kode tersebut kita cetak "Websocket dibuka" di console, lalu membuat sebuah atribut id yang berisi uuid baru. Kemudian kita memanggil stream.set_nodelay untuk mengurangi delay saat pengiriman pesan ke websocket dan ke client. Kemudian kita buat sebuah indeks baru di dalam dictionary clients yang key-nya adalah id yang telah kita buat sebelumnya, kemudian diisi dengan dictionary yang berisi atribut id dan object. Kenapa self disimpan di dalam object? karena ketika kita akan mengirimkan data kepada client lainnya, kita harus mengenal objek websocket yang mana yang akan dikirim. Karena pada dasarnya class diatas hanya mengirim kepada diri sendiri. Sehingga kita harus mengetahui objek websocket yang sudah dibuat di dalam memory untuk dikirimkan pesan kepadanya.

Lalu ada method on_open() yang menerima sebuah parameter message. Parameter tersebut akan diterima dari kode websocket dari client yang terhubung ke websocket server. Kemudian kita kirim pesan yang diterima websocket server ke pengirim itu sendiri, barulan kita kirim ke semua client yang terhubung dengan websocket server dengan cara mencacah setiap client yang dicatat di dictionary clients.

Terakhir ada method on_close yang akan dijalankan ketika websocket server berhenti atau ditutup. Anda akan menerima informasi "Websocket ditutup" di console. Sekarang mari kita tambahkan class EchoWSHandler ke pendefinisian route saat membuat objek Tornado. Kita akan tugaskan EchoWSHandler di URL "/messenger"

...................................................


if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", MainHandler),
        (r"/messenger", EchoWSHandler),
    ])

    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

Anda sudah dapat menjalan kode diatas sebagaimana mestinya. Namun untuk memanfaatkan websocket server tersebut, Anda harus membuat sebuah kode websocket di sisi client. Mari kita pindah ke bagian selanjutnya.

Menambahkan kode webocket di halaman index.html

Setelah Anda berhasil membuat kode untuk websocket server, sekarang mari kita perbaharui kode di index.html:
...................................................

<body> <h1>Demo Websocket menggunakan Tornado!</h1> <p>Selamat datang di demo Websocket...</p> <input type="button" value="Tekan Ini!" onclick="sendMsg();" /> <br/> <br/> <div id="message"> Loading.... </div> <script src="https://code.jquery.com/jquery-3.0.0.min.js"&gt;&lt;/script> <script type="text/javascript"> var ws = new WebSocket("ws://localhost:8888/messenger");

    ws.onopen = function() {
       ws.send("Hello, world");
    };

    ws.onmessage = function (evt) {
        console.log(evt.data);
        $('#message').prepend(evt.data+'&lt;br/&gt;');
    };

    function sendMsg(){
        ws.send('Pesan yang dikirimkan: ' + new Date());
    }

&lt;/script&gt;

</body>

...................................................

Pada kode diatas, kita menambahkan sebuah button yang akan menampilkan teks "Tekan Ini!" dan menjalankan sebuah function Javascript bernama sendMsg();. Kemudian kita juga membuat sebuah div dengan id message yang akan menampung semua pesan dari client yang terhubung. Kemudian kita gunakan juga jQuery yang disediakan melalui CDN. Kemudian kita buat sebuah kode websocket dengan menggunakan Javascript terbaru yang ada di web browser. Pertama kita buat sebuah objek websocket yang terhubung ke URL "ws://localhost:8888/messenger".

Lalu kita tambahkan juga function yang bernama onopen() untuk mengirim pesan awal "Hello, world" ke websocket server. Dibawahnya kita buat juga sebuah function dengan nama onmessage() yang akan menerima pesan yang dikirimkan oleh websocket server, kemudian kita tambahkan pesan baru ke bagian paling atas div dengan id message. Sehingga pesan terbaru akan selalu muncul di bagian atas. Dan terakhir kita buat sebuah function bebas yang bernama sendMsg(). Di dalamnya kita kirimkan pesan "Pesan yang dikirimkan: " yang digabungkan dengan tanggal saat ini yang di-generate di dalam web browser.

Sekarang mari kita matikan Tornado yang telah dijalankan dengan menekan Ctrl + C di console, kemudian nyalakan ulang Tornado dan cobalah akses URL "http://localhost:8888/" di web browser. Sekarang mari kita lihat hasil eksekusi dari kode - kode diatas, di web browser:

[caption id="attachment_10548" align="alignnone" width="700"]Terhubung ke websocket Terhubung ke websocket[/caption]

[caption id="attachment_10549" align="alignnone" width="700"]Dua browser terhubung dengan websocket Dua browser terhubung dengan websocket[/caption]

 

[caption id="attachment_10550" align="alignnone" width="700"]Banyak tab dan browser terhubung ke websocket Banyak tab dan browser terhubung ke websocket[/caption]

 

Penutup

Sebagai salah satu web server yang cukup populer di kalangan python developer, Tornado dapat memfasilitasi Anda untuk membangun sebuah aplikasi web ataupun menjadi websocket server. Sebagai all in one package, Anda dapat mengeksplor berbagai fitur yang ditawarkan Tornado. Selain itu Tornado pun dapat mempunyai kemampuan asynchronous programming layaknya Node.js. Anda dapat ngulik Tornado Web Server lebih jauh di https://github.com/tornadoweb/tornado/.

(rfs/tornadowebserver)