1. Perjanjian
WebSocket adalah protokol berdasarkan komunikasi dupleks penuh antara klien dan server di TCP. Ini didefinisikan dalam HTML5 dan juga merupakan salah satu spesifikasi dasar dari generasi baru WebApps.
Ini menerobos keterbatasan AJAX sebelumnya, kuncinya real-time, dan server dapat secara aktif mendorong konten ke klien! Aplikasi yang mungkin meliputi: Gaming online multipemain, obrolan langsung, pemantauan waktu nyata, desktop jarak jauh, server berita, dll.
Bagi saya sendiri, apa yang paling ingin saya coba saat ini adalah apa yang dapat dilakukan dengan kombinasi Canvas+Websocket.
2. Realisasi
Karena proses jabat tangan adalah permintaan HTTP standar, ada dua opsi untuk mengimplementasikan WebSocket: 1) Implementasi di TCP; 2) Implementasi pada perangkat lunak HTTP yang ada. Keuntungan terakhir adalah bahwa ia dapat berbagi port server HTTP yang ada dan tidak perlu mengimplementasikan kembali fungsi otentikasi dan menguraikan permintaan HTTP.
Modul node HTTP digunakan dalam contoh ini. (Lihat lampiran untuk versi TCP dan semua file)
1. Kode sisi server simpul:
var http = membutuhkan ('http'); var url = membutuhkan ('url'); // var mime = membutuhkan ('mime'); var crypto = membutuhkan ('crypto'); var port = 4400; var server = http.createServer (); server.listen (port, function () {console.log ('server berjalan di localhost:', port); server .on ('connection', function (s) {console.log ('on connection', s);}) .on ('request', onRequest) .on ('upgrade', onupgrade);}; Objek.keys (req), req.url, req ['upgrade']); if (! req.upgrade) {// Pemilihan permintaan non-upgrade: mengganggu atau berikan halaman web normal res.writeHead (200, {'tipe konten': 'teks/polos'}); res.write ('Websocket Server Works!'); } res.end (); return;}; var onupgrade = function (req, sock, head) {// console.log ('Method:', object.keys (sock)); if (req.headers.upgrade! == 'WebSocket') {console.warn ('Koneksi ilegal'); sock.end (); kembali; } bind_sock_event (sock); coba {handshake (req, sock, head); } catch (e) {console.error (e); sock.end (); }}; // Bungkus bingkai yang akan dikirim var wrap = fungsi (data) {var fa = 0x00, fe = 0xff, data = data.toString () len = 2+buffer.bytelength (data), buff = buffer baru (len); buff [0] = fa; buff.write (data, 1); buff [len-1] = fe; return buff;}// Unwrap the received frame var unwrap = function(data) { return data.slice(1,data.length-1);}var bind_sock_event = function(sock) { sock .on('data',function(buffer) { var data = unwrap(buffer); console.log('socket receive data : ',buffer,data,'/n>>> '+data); // Kirim ('Hello html5,'+date.now ()) sock.emit ('kirim', data);}) .on ('tutup', fungsi () {console.log ('socket tutup');}) .on ('end', function () {console.log ('socket end');}). sock.write (wrap (data), 'biner');})}; var get_part = fungsi (key) {var kosong = '', spaces = key.replace (// s/g, kosong) .length, bagian = key.replace (// d/g, kosong); if (! Spaces) lempar {pesan: 'Kunci yang salah:'+tombol, nama: 'HandshakeError'} return get_big_endian (bagian / spasi);} var get_big_endian = fungsi (n) {return string.fromCharCode.apply (null, [3,2,11,0] {function {i) {i) {I.Er Function (null, [3.2, function (key1, key2, head) {var sum = get_part (key1) + get_part (key2) + head.toString ('biner'); return crypto.createHash ('md5'). update (sum) .gigest ('biner');} var handshake = function (req, sock, head) {var output = [], h = req.headers, br = '/r/n'; // header output.push( 'HTTP/1.1 101 WebSocket Protocol Handshake','Upgrade: WebSocket','Connection: Upgrade', 'Sec-WebSocket-Origin: ' + h.origin, 'Sec-WebSocket-Location: ws://' + h.host + req.url, 'Sec-WebSocket-Protocol: saya-custom-chat-protocol '+br); // body var c = tantangan (h ['sec-websocket-key1'], h ['sec-websocket-key2'], head); output.push (c); sock.write (output.join (br), 'biner');}2. Kode Klien Browser:
<html><head> <title>WebSocket Demo</title></head><style type="text/css"> textarea{width:400px;height:150px;display:block;overflow-y:scroll;} #output{width:600px;height:400px;background:whiteSmoke;padding:1em .5em; warna:#000; border: none;} tombol {padding: .2em 1em;} </style> <link href = "tata letak.css" rel = "stylesheet" type = "text/css"/<body> <phe textarea id = "output" readonly = "readonly"> </TextareAA. id = "Kirim"> Kirim </button> <script type = "text/javascript"> // localhostvar socket = websocket baru ('ws: //192.168.144.131: 4400/') socket.onopen = function (e) {log (e.type); socket.send ('hello node');} socket.onclose = function (e) {log (e.type);} socket.onMessage = function (e) {log ('terima @'+tanggal baru (). Tolocaletimestring ()+'/n'+e.data); output.scrollTop = output.scrollHeight} socket.onclose = function (e) {log (e.type);} socket.addeventListener ('tutup', function () {log ('outing close event ..');}, false); // domvar id = function (id) {document. id ('output'), input = id ('input'), kirim = id ('kirim'); var log = fungsi (msg) {output.textContent += '>' +msg +'/n'} send.addeventlistener ('klik', function () {socket.send (input.value);3. Detail
Implementasi Protokol Websocket di atas protokol HTTP hanya memiliki dua langkah: Handshake dan Kirim Data.
1. Berjabat tangan
Proses jabat tangan disebut respons tantangan. Pertama, klien memulai permintaan HTTP GET bernama peningkatan, server memverifikasi permintaan, memberikan respons 101 untuk menunjukkan bahwa peningkatan protokol diterima, dan jabat tangan selesai.
Informasi jabat tangan dipercantik oleh Chrome Inspector:
Permintaan URL: WS: //192.168.144.131: 4400/pub/obrolan? Q = saya
Metode Permintaan: Dapatkan
Kode Status: 101 Tangan Protokol Websocket
Meminta header
Koneksi: Tingkatkan
Tuan rumah: 192.168.144.131: 4400
Asal: http: // localhost: 800
Sec-Websocket-Key1: P2 G 947T 80 661 JAF2
Sec-Websocket-Key2: Z ZQ ^326 5 9 = 7S1 1 7H4
SEC-WEBSOCKET-PROTOCOL :: My-Custom-Cat-Protocol
Tingkatkan: Websocket
(KEY3): 7C: 44: 56: CA: 1F: 19: D2: 0A
Header respons
Koneksi: Tingkatkan
Sec-Websocket-Location: WS: //192.168.144.131: 4400/pub/obrolan? Q = Me
Sec-Websocket-Origin: http: // localhost: 800
Sec-Websocket-Protocol: My-Custom-Chat-Protocol
Tingkatkan: Websocket
(Tantangan Respons): 52: DF: 2C: F4: 50: C2: 8E: 98: 14: B7: 7D: 09: CF: C8: 33: 40
Meminta header
Host: Host Websocket Server
Koneksi: Jenis Koneksi
Peningkatan: Jenis Upgrade Protokol
Asal: Sumber Kunjungi
Sec-Websocket-Protocol: Opsional, Nama Subprotocol, Ditentukan oleh Aplikasi itu sendiri, dan beberapa protokol dibagi dengan spasi. (*Satu opsi lain yang tersisa adalah cookie)
SEC-WEBSOCKET-Key1: Kunci Otentikasi Keamanan, Permintaan XHR tidak dapat memalsukan header permintaan yang dimulai dengan 'SEC-'.
Sec-Websocket-Key2: Sama seperti di atas
KEY3: Konten Tubuh Respons, 8 byte acak.
Header respons
Sec-Websocket-Protocol: Harus berisi nama subprotokol yang diminta
Sec-Websocket-Origin: Harus sama dengan sumber permintaan
Sec-Websocket-Location: Harus sama dengan alamat yang diminta
Respons Tantangan: Konten Badan Respons, dihitung berdasarkan tiga tombol dalam permintaan, 16 byte.
Proses perhitungan string respons pseudocode:
PART_1 = semua angka dalam KEY1 / Jumlah Spasi di Key1 Part_2 Sama seperti di atas jumlah = BIG_ENDIAN (PART_1)+BIG_ENDIAN (PART_2)+KEY3CHALLENGE_RESPONSE = MD5_DIGEST (SUM);
Strategi Perhitungan Big_endian untuk bilangan bulat 32-bit:
# Sangat mirip dengan perhitungan warna RGBA. Dari fungsi berikut, kita dapat melihat bahwa proses perhitungan var Big_endian = function (n) {return [3,2,1,0] .map (function (i) {return n >> 8*i & 0xff});} Big_endian (0xcc77aaff); // -> [204, 119, 170, 255]2. Kirim Data
Websocket API dirancang untuk memproses data menggunakan acara. Klien dapat memperoleh data lengkap selama mereka mendapatkan pemberitahuan acara tanpa memproses buffer secara manual.
Dalam hal ini, setiap data disebut bingkai. Dalam definisi spesifikasi, kepalanya harus dimulai dengan 0x00 dan atribut ekor berakhir dengan 0xff, sehingga setiap pengiriman data memiliki setidaknya dua byte.
Dalam implementasi server, kepala dan ekor harus dipotong saat menerima data; Sementara kepala dan ekor harus dikemas saat mengirim data. Formatnya adalah sebagai berikut:
# 'Halo' representasi biner asli, header permintaan dan di sini adalah pengkodean UTF8
<Buffer E4 BD A0 E5 A5 BD>
# Representasi biner yang dibungkus.
<Buffer 00 e4 bd a0 e5 a5 bd ff>
Di atas adalah semua tentang artikel ini, saya harap ini akan membantu untuk pembelajaran semua orang.