1. Vereinbarung
WebSocket ist ein Protokoll, das auf einer vollständigen Duplex -Kommunikation zwischen Clients und Servern auf TCP basiert. Es ist in HTML5 definiert und ist auch eines der grundlegenden Spezifikationen der neuen Generation von WebApps.
Es bricht die Einschränkungen des früheren Ajax durch, der Schlüssel ist Echtzeit und der Server kann den Inhalt aktiv an den Client weitergeben! Mögliche Anwendungen umfassen: Multiplayer-Online-Spiele, Live-Chat, Echtzeitüberwachung, Remotedesktop, Nachrichtenserver usw.
Was ich im Moment am meisten ausprobieren möchte, ist für mich mit Canvas+WebSocket -Kombination.
2. Realisierung
Da der Handshake -Prozess eine Standard -HTTP -Anforderung ist, gibt es zwei Optionen zur Implementierung von WebSocket: 1) Implementierung auf TCP; 2) Implementierung der vorhandenen HTTP -Software. Der letztere Vorteil besteht darin, dass vorhandene HTTP-Server-Ports freigegeben werden können und die Authentifizierungsfunktion nicht erneut implementieren und HTTP-Anforderungen analysieren müssen.
Das HTTP -Knotenmodul wird in diesem Beispiel verwendet. (Siehe Anhang für TCP -Version und alle Dateien)
1. Node Server-Side-Code:
var http = required ('http'); var url = require ('url'); // var mime = required ('mime'); var crypto = require ('crypto'); var port = 4400; var server = http.createServer (); server.Listen (port, function () {console.log ('Server läuft auf localhost:', port); server .on ('connection', function (s) {console.log ('on connection', s);} .on ('request', onRequest) .on ('upgrade', onupgrade); Object.keys (req), req.url, req ['upgrade']); if (! req.Upgrade) {// Nicht-Upgrade-Anforderung Auswahl: Interrupt oder geben Sie eine normale Webseite res.writehead (200, {'content-type': 'text/plain'}); Res.Write ('WebSocket Server funktioniert!'); } res.end (); return;}; var onupgrade = function (req, sock, head) {// console.log ('methode:', Object.keys (Socken)); if (req.headers.upgrade! == 'webocket') {console.warn ('illegale Verbindung'); Sock.end (); zurückkehren; } bind_sock_event (Sock); Versuchen Sie {Handshake (Req, Sock, Kopf); } catch (e) {console.Error (e); Sock.end (); }}; // Wickeln Sie den zum gesendeten Bild ein. Buff [0] = FA; Buff.Write (Daten, 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); // send ('Hallo html5,'+date.now ()) sock.emit ('send', data); Sock.Write (Wrap (Daten), 'Binary'); if(!spaces) throw {message:'Wrong key: '+key,name:'HandshakeError'} return get_big_endian(part / spaces);}var get_big_endian = function(n) { return String.fromCharCode.apply(null,[3,2,1,0].map(function(i) { return n >> 8*i & 0xff }))}var challenge = Funktion (KEY1, KEY2, Kopf) {var sum = get_part (key1) + get_part (key2) + head.toString ('binär'); return crypto.createhash ('md5'). Update (sum) .Digest ('binär');} var Handshake = Funktion (Req, Sock, Kopf) {var output = [], h = req.Headers, br = '/r/n'; // Header output.push ('http/1.1 101 WebSocket Protocol Handshake', 'Upgrade: WebSocket', 'Verbindung: Upgrade', 'Sec-Websocket-Origin:' + H.origin, 'Sec-Webet-Lokalisierung: WS: //' + H.HOST + REQ.URL, 'SECBEBSOCKET: My-Custom-Chat-Protocol '+Br); // Body var c = Herausforderung (h ['Sec-Websocket-Key1'], h ['Sec-Websocket-Key2'], Kopf); output.push (c); Sock.Write (output.join (Br), 'Binary');};2. Browser -Clientcode:
<html> <Head> <titels> WebSocket-Demo </title> </head> <style type = "text/css"> textArea {width: 400px; Höhe: 150px; Anzeige: Block; Overflow-y: Scroll;} #output {width: 600px; .5em;color:#000;border:none;} button{padding:.2em 1em;}</style><link href="layout.css" rel="stylesheet" type="text/css" /> <body><textarea id="output" readonly="readonly"></textarea><br><textarea id="input"></textarea><button id = "senden"> senden </button> <skript type = "text/javaScript"> // localhostvar socket = new WebSocket ('ws: //192.168.144.131: 4400/') Socket.onopen = Funktion (e) {log (e.type); Socket.Send ('Hello Node');} Socket.Onclose = Funktion (e) {log (e.type);} Socket.OnMessage = Funktion (e) {log ('empfangen @'+New Date (). Tolocaletimestring ()+'/n'+E.Data); output.scrolltop = output.scrollHeight} socket.onclose = function (e) {log (e.type);} socket. id ('input'), send = id ('send'); var log = function (msg) {output.textContent += '>' +msg +'/n'} send.addeventListener ('click', function () {socket.send (value);}, false);3. Details
Die Implementierung von WebSocket -Protokoll über dem HTTP -Protokoll enthält nur zwei Schritte: Handshake und Senden.
1. Händeschütteln
Der Handshake-Prozess wird als Challenge-Antwort bezeichnet. Zunächst initiiert der Client eine HTTP -GET -Anforderung mit dem Namen Upgrade, der Server überprüft die Anfrage, gibt eine Antwort von 101 an, um anzuzeigen, dass das Protokoll -Upgrade akzeptiert wird und der Handschlag abgeschlossen ist.
Die von Chrome Inspector verschönernden Handshake -Informationen:
URL anfordern : WS: //192.168.144.131: 4400/pub/chat? Q = me
Anforderungsmethode: Get
Statuscode: 101 WebSocket -Protokollhandshake
Anfordern von Headern
Verbindung: Upgrade
Gastgeber: 192.168.144.131: 4400
Herkunft: 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-Chat-Protocol
Upgrade: Websocket
(KEY3): 7C: 44: 56: CA: 1F: 19: D2: 0A
Reaktionsüberschriften
Verbindung: Upgrade
Sec-Websocket-Standort: WS: //192.168.144.131: 4400/Pub/Chat? Q = Me
Sec-Websocket-Origin: http: // localhost: 800
Sec-Websocket-Protokoll: My-Custom-Chat-Protocol
Upgrade: Websocket
(Herausforderungsantwort): 52: DF: 2C: F4: 50: C2: 8E: 98: 14: B7: 7d: 09: CF: C8: 33: 40
Header anfordern
Host: WebSocket Server Host
Verbindung: Verbindungstyp
Upgrade: Protokoll -Upgrade -Typ
Herkunft: Besuchen Sie die Quelle
Sec-Websocket-Protokoll: Optional, subprotokollischer Name, definiert durch die Anwendung selbst, und mehrere Protokolle werden durch Leerzeichen geteilt. (*Eine andere Option links ist Cookies)
SEC-Webocket-Key1: Sicherheitsauthentifizierungsschlüssel, XHR-Anfrage kann keine Anfrage-Header mit 'Sec-' auffällt.
Sec-Websocket-Key2: Wie oben
Key3: Reaktionskörperinhalt, 8 Bytes zufällig.
Antwortkopf
Sec-Webocket-Protocol: Muss den angeforderten SubproTocol-Namen enthalten
Sec-Websocket-Origin: Muss gleich der Quelle der Anfrage sein
Sec-Websocket-Location: Muss der angeforderten Adresse gleich sein
Herausforderungsantwort: Der Reaktionskörperinhalt, berechnet basierend auf den drei Schlüssel in der Anfrage, 16 Bytes.
Reaktionszeichenfolge Berechnungsprozess Pseudocode:
part_1 = alle Zahlen in Key1 / Anzahl der Leerzeichen in Key1 part_2 wie oben wie oben = big_endian (part_1)+big_endian (part_2)+key3Challenge_Response = Md5_Digest (sum);
Big_endian Berechnungsstrategie für 32-Bit-Ganzzahlen:
# Es ist der RGBA -Farbberechnung sehr ähnlich. Aus der folgenden Funktion können wir sehen, dass der Berechnungsprozess var big_endian = function (n) {return [3,2,1,0] .map (Funktion (i) {return n >> 8*i & 0xff});} Big_endian (0xcc77aAff); // -> [204, 119, 170, 255]2. Senden Sie Daten
Die WebSocket -API wurde entwickelt, um Daten mithilfe von Ereignissen zu verarbeiten. Clients können vollständige Daten erhalten, solange sie Ereignisbenachrichtigungen erhalten, ohne den Puffer manuell zu verarbeiten.
In diesem Fall wird jede Daten als Rahmen bezeichnet. In der Spezifikationsdefinition muss sein Kopf mit 0x00 beginnen und das Schwanzattribut endet mit 0xff, sodass jedes Senden jedes Daten -Sendens über mindestens zwei Bytes verfügt.
In der Server -Implementierung müssen Kopf und Schwanz beim Empfangen von Daten abgeschnitten werden. während Kopf und Schwanz beim Senden von Daten verpackt werden müssen. Das Format lautet wie folgt:
# 'Hallo' ursprüngliche binäre Darstellung, der Anforderungsheader und hier sind UTF8 -Codierungen
<Puffer E4 BD A0 E5 A5 BD>
# Die eingewickelte binäre Darstellung.
<Puffer 00 E4 BD A0 E5 A5 BD FF>
Das Obige dreht sich alles um diesen Artikel, ich hoffe, es wird für das Lernen aller hilfreich sein.