Daftar program spesifik untuk tiap bahasa pemrograman:
  1. Bermain WebSocket (RFC 6455) Server dengan Netty
  2. Script Java WebSocket (RFC 6455) Server
  3. Script Php WebSocket (RFC 6455) Server
  4. Script Python WebSocket (RFC 6455) Server
  5. Script Ruby WebSocket (RFC 6455) Server
  6. Script Node.js WebSocket (RFC 6455) Server
  7. Script C# WebSocket (RFC 6455) Server
  8. Script C WebSocket (RFC 6455) Server (unfinished yet)
Framework WebSocket untuk pengembangan sehari-hari para Web Developer:
  1. Node.js: socket.io
  2. Java: Java API for WebSocket
  3. PHP: Ratchet
  4. Python: Tornado

Apa itu WebSocket?

WebSocket merupakan solusi untuk masalah penyampaian informasi yang tidak diawali terlebih dahulu oleh pengguna web. Sebelum WebSocket muncul, umumnya programmer web akan menggabungkan setTimeout() atau setInterval() dengan ActiveXObject( "Microsoft.XMLHTTP" ), XMLHttpRequest(), $.ajax(), atau $.getJSON() untuk membuat seolah-olah informasi yang disajikan realtime. Serta, tahukah kita, latar belakang kenapa React.js terlahir? facebook tidak bisa membuat indikator notifikasi di facebook.com, maka terlahirlah React.js. cekidot link berikut: The Sad State of Web Development by +Drew Hamlett 

Namun sejak desember 2011 ketika protokol WebSocket (RFC 6455) dirilis. Programmer web bisa menggunakan class WebSocket yang telah disediakan disetiap Web Browser berikut:
Fitur Chrome Firefox (Gecko) Internet Explorer Opera Safari Android Browser Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
RFC 6455 16 11.0 (11.0) 10 12.10 6.0 4.4 (KitKat) 11.0 (11.0) ? 12.10 6.0

Ciri Aplikasi Web yang memerlukan WebSocket

Jika anda pernah melakukan pelelangan di ebay.com jaman 1995 atau membuat akun surel yahoo.com, untuk mengecek apakah terdapat bid baru atau surel baru anda perlu memuat ulang halaman situs tersebut. Sejak 18 Maret 1999 yaitu hari lahirnya Internet Explorer 5.0 berkat class ActiveXObject dan fungsi setTimeout()/setInterval() anda tidak perlu memuat ulang halaman secara manual untuk mengecek adanya bid baru atau surel baru, karena class ActiveXObject dapat diatur setiap rentang waktu tertentu untuk mengirim request http ke web server apakah terdapat pesan baru atau bid baru, class ActiveXObject kini telah berubah menjadi class XMLHttpRequest.

Masalah dengan setTimeout() atau setInterval()

Waktu interval()/timeout() yang kecil misalkan 1 detik berakibat memboroskan bandwidth dikarenakan sifat ketidak pastian atau keacakan waktu kedatangan kejadian eksternal tersebut. Setiap kali request Http dikirimkan ke server paling minimal melibatkan 49 byte data (contoh: GET / http/1.1\r\nHost: a.id\r\nConnection: close\r\n\r\n). Sedangkan WebSocket hanya 6 byte saja, yaitu byte pertama berisi kode operasi, byte kedua berisi ukuran muatan, byte ke3-6 berupa byte penopeng, dan byte seterusnya tergantung ukuran data sama sepeti muatan header Http. Untuk data perbandingan yang detil silahkan baca situs berikut [1].
Semua use case yang disebutkan diatas dapat diimplementasikan dengan WebSocket karena sifat koneksi WebSocket yang persistent atau keep-alive sehingga server bisa meneruskan respon/kejadian tanpa browser mengirimkan request berulang-ulang seperti penggunaan setTimeout() atau setInterval() yang memanggil class XMLHttpRequest atau fungsi $.getJSON() milik jQuery. Selain itu header request websocket hanya dikirim sekali ke web server, selanjutnya browser tidak perlu mengirim header request berulang-ulang cukup bingkai websocket saja begitu juga server websocket, selain itu biaya pembuatan koneksi TCP lebih kecil karena hanya terjadi ketika handshake saja.

Adapun use case lainnya yang sama-sama acak sifat terjadinya antara lain:
  1. Menampilkan broadcast kejadian pasien datang dan obat diapotik sudah diinput di Rumah Sakit Islam PKU Muhammadiyah Kutoarjo. Untuk penjelasan teknis, saya tuliskan di postingan saya berikut Penggabungan pola RPC dan Publish-Subscribe dengan AngularJS Service dan Tomcat WebSocket API.
  2. Seperti SAP APO Alert Monitor, memberikan notifikasi ketika nilai statistik tertentu mencapai batas baik MAD atau tracking signal, jadi sistem akan memberi peringatan ketika bias, outlier (pencilan), atau perubahan tren terjadi, atau order melebihi forecast time series yang telah dilakukan.
  3. Menampilkan notifikasi harga harga saham (stock quote) tertentu seperti BulletProof WallStreetWeb ketika Januari 1996 masih di implementasikan menggunakan Java Applet & java-odbc
  4. Menampilkan perubahan koordinat marker di directive angular-google-maps dengan koordinat yang dikirim dari LocationListener android menggunakan pustaka WebSocket Tyrus Standalone Client dengan koordinat gradle berikut 'org.glassfish.tyrus.bundles:tyrus-standalone-client:1.12' seperti projek coding.net ku nantinya: android-wisata-solo
  5. Menampilkan notifikasi tawaran di situs pelelangan
  6. Menampilkan pesan chatting (yah use case lama) misal antar android dengan web seperti projek gitku di AngularJS-Socket.IO-NodeJS
  7. Menampilkan notifikasi jika suhu reaktor nuklir telah mencapai ambang batas

Tantangan Menggunakan WebSocket

Disetiap perantara yang berada diantara browser dan server memiliki pengaturan untuk memutus koneksi TCP yang telah terbentuk (established), ada yang diukur sejak awal koneksi terbentuk, ada juga yang baru diukur setelah koneksi menganggur (idle), di mikrotik secara default tcp-established-timeout diatur satu hari, jadi koneksi tcp akan terputus jika koneksi telah berumur satu hari meskipun sedang ada data yang mengalir, sedangkan untuk pemutusan koneksi yang menganggur (idle) dalam artian tidak ada data sama sekali yang sedang mengalir itu ada yang 30 detik. Untuk mengatasi koneksi yang menganggur server WebSocket perlu mengirimkan pesan keep-alive untuk mereset counter pemutus koneksi berupa pesan ping, karena di JavaScript tidak terdapat fungsi untuk mengirimkan pesan ping. Serta terdapat pengaturan di linux agar congestion window tidak menurun ke nilai initial jika flag berikut diset 1 net.ipv4.tcp_slow_start_after_idle = 0, karena jika diset 1 congestion window akan dipotong setengahnya setiap waktu Round Trip Time pengangguran. Selain itu, masalah perubahan IP Address ketika jaringan ponsel berganti, good luck :3

Apa itu WebSocket server?

Server WebSocket merupakan aplikasi TCP yang secara default mendengarkan koneksi di port 80 atau 443. Server WebSocket bisa diimplementasikan disembarang bahasa pemrograman yang memiliki pustaka Berkeley sockets, seperti C, C#, Node.js, Ruby, Python, PHP, Java. 

Persyaratan Belajar

Sebelum mulai membaca tulisan ini anda perlu tahu bagaimana protokol HTTP bekerja dan punya pengalaman pemrograman tingkat menengah. Tergantung dukungan bahasa, pengetahuan pustaka tcp juga diperlukan. Cakupan panduan ini untuk menyajikan pengetahuan minimum untuk menulis Server WebSocket.

Langkah 1: Jabat Tangan WebSocket

Pertama-tama, program server harus mendengarkan koneksi masuk menggunakan java ServerSocket atau php socket_create_listen(). Sebagai contoh, diasumsikan server anda membuka koneksi di localhost atau 127.0.0.1, port 80, dan server socket anda merespon permintaan GET di alamat root /, kalau di apache berada di direktori htdocs langsung, kalau di tomcat di webapps/ROOT. Jabat Tangan seperti isi header http GET tapi ada beberapa tambahan. Permintaan tersebut merupakan jembatan dari protokol HTTP ke protokol WS. Di dalam jabat tangan, detil koneksi dinegosiasikan seperti Origin: apakah sesuai, dsb. (lebih lanjut tentang Cross Origin Resource Sharing).

Permintaan Jabat Tangan dari client WebSocket

Meski anda membangun server, client yang akan memulai proses. Jadi anda perlu tahu bagaimana cara menerjemahkan header yang dikirim client tersebut. client akan mengirimkan permintaan HTTP standar yang terlihat sebagai berikut (versi HTTP harus 1.1 atau lebih baru seperti HTTP/2, dan metode permintaan harus GET):

GET / HTTP/1.1\r\n
Host: localhost\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n
Sec-WebSocket-Version: 13\r\n
\r\n

Dari header yang dikirimkan oleh browser atau client websocket lainnya tersebut, hanya header Sec-WebSocket-Key yang perlu kita perhatikan dalam diskusi ini, penjelasan detil mengenai perlakuan untuk header lain tentu saja di rfc 6455 sendiri, hho :3 tapi yang pasti kalau aturan http 1.1 header Host dan Connection itu wajib disertakan, tapi untuk program server ecek-ecek ini cukup memperhatikan header Sec-WebSocket-Key saja

Respon Jabat Tangan Server

Ketika server mendapatkan permintaan jabat tangan dari client tesebut, server harus membalas dengan respon http yang terlihat sebagai berikut:

HTTP/1.1 101 Switching Protocols\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n
\r\n

Jadi langkah-langkahnya,
  1. Dapatkan nilai header Sec-WebSocket-Key tanpa spasi depan dan belakang
  2. Gabung nilai header dengan "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
  3. Hitung nilai SHA-1
  4. Encode dengan Base64
  5. Jadikan hasil penyandian basis64 sebagai nilai header Sec-WebSocket-Accept
Jadi jika nilai header Sec-WebSocket-Key itu dGhlIHNhbXBsZSBub25jZQ== maka nilai header Sec-WebSocket-Accept yang server harus berikan adalah s3pPLMBiTxaQ9kYGzzhZRbK+xOo=. Setelah server mengirimkan header tersebut, jabat tangan sudah selesai dan koneksi jangan diputus seperti ketika isi header http Connection: close, tapi disimpan dalam variable guna untuk bertukar data dikemudian waktu.

Langkah 2: Bertukar Bingkai Data

Baik client atau server bisa memilih untuk mengirim pesan kapanpun. Jika anda menggunakan method send() milik class WebSocket() di JavaScript untuk mengirim pesan teks "abcdef", maka jika di Java method read() milik class InputStream ataupun di php fungsi socket_read() akan mengembalikan data seperti berikut:
129134167225225210198131130182194135
atau untuk mempermudah pemahaman pembaca sebaiknya angka diatas langsung diterjemahkan kedalam bilangan biner menjadi sebagai berikut (hho, mempermudah bijimane, angka apaan ituh):
urutan12345678
110000001
210000110
310100111
411100001
511100001
611010010
711000110
810000011
910000010
1010110110
1111000010
1210000111
Penjelasan tabel:
  1. bit pertama dari byte pertama diatas, atau dalam tabel, kolom ke 2 baris ke 2, merupakan bit penanda apakah bingkai tersebut merupakan bingkai parsial atau bingkai final, jika 1 maka bingkai final jika 0 maka bingkai parsial. Karena pembacaan di fungsi socket_read() php & java in.read() paling kecil byte, maka untuk mendapatkan bit pertama byte pertama dari hasil pemanggilan fungsi socket_read()/read() tersebut anda perlu melakukan BITWISE AND dengan angka desimal 128 atau angka biner 10000000. Jadi misal berdasar tabel diatas, anda bisa langsung menentukan bahwa bingkai pesan "abcdef" merupakan bingkai pesan final, karena bit pertama bernilai 1, lalu bagaimana cara mendapatkannya dalam bahasa pemrograman? ya cukup begini kalau di php: socket_read($koneksi, 1) & 128 coba kilas balik ke pelajaran logika matematika kelas 10 SMA, kalau diterangkan dengan matematika
    10000001
    10000000
    --------AND
    10000000
    logika AND akan bernilai benar jika kedua nilai bernilai benar, selain itu salah. nah di sini hasilnya angka desimal 128 atau angka biner 10000000, berarti anda tidak perlu menyimpan secara sementara isi muatan yang dibawa bingkai ini, tapi kalau hasilnya angka desimal 0, maka muatan perlu digabung (append atau concatenate) dengan bingkai berikutnya sampai ditemui angka desimal 128 atau penanda bahwa bingkai tersebut sudah final.
  2. bit kedua, ketiga, dan keempat merupakan bit reserved yang bisa diabaikan untuk sekarang.
  3. bit kelima, keenam, ketujuh dan kedelapan merupakan bit penentu operasi bingkai (kalau di protokol tekstual seperti HTTP penentu operasi merupakan kata pertama di baris pertama sebelum spasi yaitu bisa GET/POST/PUT/DELETE). Di dalam protokol WebSocket (RFC 6455) terdapat 6 jenis operasi yaitu:
    1. angka desimal 0 merepresentasikan bahwa bingkai pesan merupakan bingkai data parsial.
    2. angka desimal 1 merepresentasikan bahwa bingkai pesan merupakan bingkai data teks.
    3. angka desimal 2 merepresentasikan bahwa bingkai pesan merupakan bingkai data biner.
    4. angka desimal 8 merepresentasikan bahwa bingkai pesan merupakan bingkai kontrol tutup koneksi.
    5. angka desimal 9 merepresentasikan bahwa bingkai pesan merupakan bingkai kontrol ping.
    6. angka desimal 10 merepresentasikan bahwa bingkai pesan merupakan bingkai kontrol pong.
    Untuk mendapatkan kode operasi ini, yaitu bit ke 5, ke 6, ke 7, dan ke 8, byte pertama perlu di BITWISE AND denga angka desimal 15 atau angka biner 1111. Jadi 10000001 AND 00001111 = 00000001, Contoh program WebSocket dengan pesan biner pengenalan wajah dengan java-opencv
  4. bit pertama dari byte kedua diatas, atau dalam tabel, kolom ke 2 baris ke 3, merupakan bit penanda apakah terdapat field penopeng sebanyak 4 byte setelah byte kedua atau jika merujuk kepada tabel, bit ini akan menentukan keberadaan baris ke 3, baris ke 4, baris ke 5, dan baris ke 6. Jika 1 maka ada field penopeng jika 0 maka tidak ada field penopeng. Semua bingkai yang dikirim client websocket wajib di set 1, sedangkan semua bingkai yang dikirim server websocket wajib di set 0. Jika dilanggar maka koneksi wajib diputus. Untuk mendapatkan bit ini ya sama seperti langkah pertama, perlu di BITWISE AND dengan desimal 128.
  5. bit ke 2, ke 3, ke 4, ke 5, ke 6, ke 7, dan ke 8 dari byte kedua diatas menentukan ukuran (size) atau panjang (length) dari muatan yang dibawa bingkai baik yang satu bingkai penuh atau beberapa bingkai parsial. Untuk menentukannya anda perlu mengikuti langkah berikut:
    1. lakukan operasi BITWISE AND antara byte kedua dengan angka desimal 127 atau angka biner 1111111, misal berdasar tabel diatas 10000110 AND 01111111 akan menghasilkan 00000110 atau 6, berarti bingkai pesan ini berisi 6 byte data, jumlah ini sesuai jumlah karakter "abcdef". Tapi ada tapinya.
    2. Jika hasil operasi BITWISE AND mulai dari 0 hingga 125, maka itu ukuran muatan bingkai.
    3. Jika hasil operasi BITWISE AND adalah 126, maka abaikan angka 126 ini, dan baca 2 byte setelah byte ini, maka itulah panjang muatan, tipe datanya berupa unsigned short, rentang nilai yang akan berada di 2 byte ini bermula dari angka desimal 126 hingga desimal 65535, atau angka biner 01111110 hingga biner 1111111111111111. Jika sampai berada dibawah 126 maka koneksi digagalkan. Karena data terdiri dari 2 byte data, maka perlu digabung agar menjadi angka bertipe unsigned short, jadi cara menggabung 2 byte menjadi satu angka caranya sebagai berikut:
      1. pembacaan byte pertama setelah byte berisi ukuran bingkai dengan fungsi socket_read() di shift kekiri sebanyak 8
      2. hasil shift tadi dilakukan operasi bitwise OR dengan pembacaan byte setelah byte berisi ukuran bingkai
      jadi, misal data di byte pertama itu 10000001 adalah bingkai final bertipe teks, lalu byte kedua bernilai 11111110 yang bermakna rentang nilai bermula dari 126 hingga 65535 maka baca 2 byte setelah byte kedua ini, serta bit pertama di byte kedua ini menandakan terdapat 4 byte penopeng setelah 2 byte yang berisi ukuran muatan bingkai, lalu misal pembacaan byte ketiga adalah angka biner 00000001 dan pembacaan byte keempat adalah angka biner 00000001, bila byte ketiga dilakukan operasi shift kekiri sebanyak 8 (di java & php dengan operator << ) hasilnya adalah angka biner 0000000100000000 yang bernilai desimal 256, lalu hasil operasi shift dilakukan operasi bitwise OR dengan pembacaan byte ketiga yang bernilai biner 00000001 hasilnya adalah angka biner 0000000100000001 atau angka desimalnya 257, jadi artinya bingkai pesan teks ini berisi data teks sebanyak 257 karakter.
    4. Jika hasil operasi BITWISE AND adalah 127, maka abaikan angka 127 ini, dan baca 8 byte setelah byte ini, maka itulah panjang muatan, tipe datanya berupa long atau nilai maksimum adalah 63 bit paling belakang berisi 1 (satu) semua, sedangkan paling depan hanya satu angka 0. rentang nilai yang akan berada di 8 byte ini bermula dari angka desimal 65536 atau angka biner 10000000000000000 hingga angka desimal 9,223,372,036,854,775,807 atau angka binernya berupa angka 1 sebanyak 63 digit. jika melanggar aturan koneksi digagalkan. cara konversinya googling banyak :P hho, kata kunci "how to convert byte array to long", udah gituh ajah. kalau singkatnya tanpa penjelasan cukup begini:
      ukuranMuatan = 0L;
      for (int i = 0; i < 8; i++) {
          ukuranMuatan |= inputStream.read() << (7 - i) * 8;
      }
      
  6. Untuk kasus contoh ini karena muatan data berukuran 6 byte atau 6 karakter atau dengan kata lain ukuran muatan kurang dari 126 dan bit ke 1 di byte ke 2 bernilai 1, maka 4 byte setelah byte kedua berisi byte penopeng, yaitu angka desimal 167, 225, 225, 210. Maka untuk dapat mengartikan byte muatan perlu dilakukan operasi bitwise XOR antara byte ke 3,4,5,6 dengan setiap isi byte muatan yang berada di byte ke 7, ke 8, ke 9, ke 10, ke 11, dan ke 12. Jadi byte ke 3 XOR byte ke 7, byte ke 4 XOR byte ke 8, byte ke 5 XOR byte ke 9, byte ke 6 XOR byte ke 10, diulang lagi kuncinya byte ke 3 XOR byte ke 11, byte ke 4 XOR byte ke 12

Pemecahan Pesan

Field FIN dan kode operasi bersama-sama menentukan apakah sebuah pesan terbagi kedalam beberapa bingkai atau tidak. Hal ini disebut dengan pemecahan pesan. Pemecahan hanya tersedia pada kode operasi 0 yaitu berupa bingkai lanjutan, kode operasi 1 berupa bingkai berisi pesan teks, dan kode operasi 2 berupa bingkai berisi pesan biner. Nah jika kode operasi 0, server harus menggabungkan isi muatan bingkai yang ditemui pertama kali dengan bit pertama pada byte pertama bernilai 0 hingga ditemui lagi bit pertama pada byte pertama bernilai 1. Berikut ilustrasi sederhana EchoServer untuk demonstrasi pemecehan pesan, dimana server mengirimkan kembali pesan yang dikirimkan oleh client yang mengirim pesan teks terpisah, tapi saya sendiri belum bereksperimen kapan sebuah pesan akan terpecah ketika menggunakan firefox atau android. Pesan pertama dikirim dalam satu bingkai, sedangkan pesan kedua dikirim dalam tiga bingkai. field FIN dan kode operasi hanya ditunjukkan untuk sisi client:
Client: FIN=1, kodeOperasi=1, pesan="halo"
Server: (bingkai penuh langsung diolah) halo.
Client: FIN=0, kodeOperasi=1, pesan="satu "
Server: (menunggu, pesan ini akan digabung dengan pesan berikutnya)
Client: FIN=0, kodeOperasi=0, pesan=" dua "
Server: (menunggu, pesan ini akan digabung dengan pesan berikutnya)
Client: FIN=1, kodeOperasi=0, pesan="tiga"
Server: (pesan komplit, pesan digabung semua) satu dua tiga
Perhatikan bingkai pertama mengandung seluruh pesan (field FIN=1 dan opcode!=0x0), jadi server bisa mengolah atau meresponnya langsung. Bingkai kedua yang dikirim oleh client punya muatan teks (kodeOperasi=1), tapi seluruh pesan belum datang seluruhnya (FIN=0). Seluruh bagian pesan yang tersisa dikirim dengan kode operasi pesan lanjutan (kodeOperasi=0), dan bingkai terakhir ditandai dengan field FIN=1. Bagian 5.4 di RFC 6455 mendeskripsikan pemecahan pesan.

Langkah 3: Ping dan Pong: Me-reset idle timeout di makelar

Di suatu waktu setelah selesai jabat tangan, baik client atau server bisa memilih untuk mengirim ping ke pihak yang lain. Ketika ping diterima, komunikan atau resipien atau penerima harus membalas pesan pong dengan isi pesan yang sama sesegera mungkin. Server bisa menggunakan hal tersebut untuk memastikan client masih terhubung. Kode operasi ping adalah angka desimal 9 dan kode operasi pong punya kode operasi angka desimal 10. Jumlah maksimal muatan untuk ping dan pong adalah 125 byte. Anda mungkin juga mendapat pesan pong tanpa pernah mengirim ping, abaikan pesan tersebut jika telah terjadi.

Langkah 4: Menutup koneksi

Untuk menutup koneksi baik client atau server bisa mengirim bingkai kontrol dengan kode operasi angka desimal 8 (lebih detil di Bagian 5.5.1). Ketika menerima bingkai pesan tersebut. Pihak pertama bisa menutup koneksi tersebut. Segala data yang datang setelah kontrol penutup terkirim bisa diabaikan.

Referensi

[1] A. Gupta, 'REST vs WebSocket Comparison and Benchmarks', Miles to go 3.0 ..., 2014. [Online]. Available: http://blog.arungupta.me/rest-vs-websocket-comparison-benchmarks/. [Accessed: 11- Nov- 2015].
[2] L. Dignan, 'Commentary: P&G, Gillette could make IT waves', Baselinemag.com, 2015. [Online]. Available: http://www.baselinemag.com/c/a/Business-Intelligence/Commentary-PG-Gillette-could-make-IT-waves. [Accessed: 12- Nov- 2015].
[3] Belajar Management, 'Penggolongan biaya dalam Persediaan', 2011. [Online]. Available: https://belajarmanagement.wordpress.com/2011/04/25/penggolongan-biaya-dalam-persediaan/. [Accessed: 12- Nov- 2015]. 

Reaksi:

You Might Also Like:

Add your comment Hide comment

Hello, how may we help you? Just send us a message now to get assistance.

Facebook Messenger ×