Websocket protocol details and simple instance code, websocket details examples
Websocket protocol details
For more information about the websocket protocol, see other articles.
WebSocket keywords
HTML5 protocol, real-time, full-duplex communication, persistent connection
Benefits of WebSocket over traditional Http
- Only one TCP connection is established between the client and the server, and fewer connections can be used.
- The WebSocket server can push data to the client. For example, the real-time security information is fed back to the client (which is critical). The real-time weather data is more flexible than the http request response mode.
- Lighter protocol headers to reduce data transfer volumes
Data frame format
Manually created data frame format
/*** Fin | masked | * srv1 | length | * srv2 | (7bit | mask data | payload * srv3 | 7 + 2 bytes | 4 bytes | opcode of real data | 7 + 64 bytes | * (4 Bit) */
Perform the following operations:
1. the first 8 bits (one byte)
-Fin: whether the data is sent completely. If it is set to 1, it is set to 0.
-Srv1, srv2, and srv3: reserved for later use
-Opcode: indicates the data type operation code, which is 4 bits.
TEXT: 1, text string
BINARY: 2, BINARY data, usually used to save images
CLOSE: 8. CLOSE the connected data frame.
PING: 9, heartbeat detection. Ping
PONG: 10, heartbeat detection. Pong
Var events = require ('events'); var http = require ('http'); var crypto = require ('crypto '); var util = require ('util '); /*** data type operation code TEXT string * BINARY data is often used to save the photo * PING, PONG is used for heartbeat detection * CLOSE closes the connected data frame (there are a lot of code to CLOSE the connection 1001,1009, 1007,1002) */var opcodes = {TEXT: 1, BINARY: 2, CLOSE: 8, PING: 9, PONG: 10}; var WebSocketConnection = function (req, socket, upgradeHead) {"use strict"; var self = this; var key = HashWebSocketKey (req. headers ['sec-websocket-key']);/*** write header */socket. write ('HTTP/1.1 101 Web Socket Protocol Handshake \ r \ n' + "Upgrade: WebSocket \ r \ n" + "Connection: upgrade \ r \ n "+" sec-websocket-accept: "+ key + '\ r \ n \ r \ n');/*** receive data */socket. on ('data', function (buf) {self. buffer = Buffer. concat ([self. buffer, buf]); while (self. _ processBuffer () {}}); socket. on ('close', function (had _ Error) {if (! Self. closed) {self. emit ("close", 1006); self. closed = true ;}}); this. socket = socket; this. buffer = new Buffer (0); this. closed = false ;}; // websocket connection inheritance event util. inherits (WebSocketConnection, events. eventEmitter);/* data sending function **/WebSocketConnection. prototype. send = function (obj) {"use strict"; var opcode; var payload; if (Buffer. isBuffer (obj) {opcode = opcodes. BINARY; payload = obj;} else if (ty Peof obj) {opcode = opcodes. TEXT; // create a UTF-8 encoded string: payload = new Buffer (obj, 'utf8');} else {throw new Error ('cannot send object. must be string of buffer');} this. _ doSend (opcode, payload) ;};/* closes the connection function **/WebSocketConnection. prototype. close = function (code, reason) {"use strict"; var opcode = opcodes. CLOSE; var buffer; if (code) {buffer = new Buffer (Buffer. byteLength (reason) + 2); buf Fer. writeUInt16BE (code, 0); buffer. write (reason, 2);} else {buffer = new Buffer (0);} this. _ doSend (opcode, buffer); this. closed = true;}; WebSocketConnection. prototype. _ processBuffer = function () {"use strict"; var buf = this. buffer; if (buf. length <2) {return;} var idx = 2; var b1 = buf. readUInt8 (0); // read the first 8-bit var fin = b1 & 0x80; // if it is 0x80, it indicates that the transmission ends. var opcode = b1 & 0x0f; // truncate the last four digits of the first byte v Ar b2 = buf. readUInt8 (1); // read the second byte var mask = b2 & 0x80; // determine whether a mask exists. The client must have var length = b2 | 0x7f; // obtain the true value of the length attribute, if (length> 126) {if (buf. length <8) {return; // if it is greater than 125, and the number of bytes is smaller than 8, it is obviously not required.} if (length = 126) {// The obtained value is 126, indicating that the last two bytes are used to indicate data length = buf. readUInt16BE (2); // read the 16bit value idx + = 2; // + 2} else if (length = 127) {// The obtained value is 126, the last 8 bytes are used to indicate the Data Length var highBits = buf. readUInt3 2BE (2); // (1/0) 1111111 if (highBits! = 0) {this. close (1009, ""); // 1009 close the code, indicating that the data is too large} length = buf. readUInt32BE (6); // the length from the sixth to the tenth bytes is the actual data length idx + = 8;} if (buf. length <idx + 4 + length) {// 4 is the number of mask bytes return;} var maskBytes = buf. slice (idx, idx + 4); // obtain the mask data idx + = 4; // move the Pointer Forward to the real data segment var payload = buf. slice (idx, idx + length); payload = unmask (maskBytes, payload); // decodes real data this. _ handleFrame (opcode, payload); // process the operation code this. buffer = buf. slice (idx + length); // cache buffer return true ;};/*** handle different operation codes * @ param operation code * @ param data */WebSocketConnection. prototype. _ handleFrame = function (opcode, buffer) {"use strict"; var payload; switch (opcode) {case opcodes. TEXT: payload = buffer. toString ('utf8'); // this. emit ('data', opcode, payload); // Buffer. toString () default utf8 here is the break intentionally indicated; case opcodes. BINARY: // BINARY file direct delivery payload = buffer; this. emit ('data', opcode, payload); break; case opcodes. PING: // send ping to respond to this. _ doSend (opcodes. PING, buffer); break; case opcodes. PONG: // do not process break; case opcodes. CLOSE: // close there are many CLOSE code let code, reason; // used to get the close code and the reason for closing if (buffer. length> = 2) {code = buffer. readUInt16BE (0); reason = buffer. toString ('utf8', 2);} this. close (code, reason); this. emit ('close', code, reason); break; default: this. close (1002, 'unknown opcode') ;}};/*** function for actually sending data * @ param opcode operation code * @ param payload data * @ private */WebSocketConnection. prototype. _ doSend = function (opcode, payload) {"use strict"; this. socket. write (encodeMessage (opcode, payload); // It is directly sent through socket after encoding }; /*** encode data ** @ param opcode operation code * @ param payload data * @ returns {*} */var encodeMessage = function (opcode, payload) {"use strict "; var buf; var b1 = 0x80 | opcode; var b2; var length = payload. length; if (length <126) {buf = new Buffer (payload. length + 2 + 0); b2 | = length; // buffer, offset buf. writeUInt8 (b1, 0); // read the first 8-bit buf. writeUInt8 (b2, 1); // read 8-15bit // Buffer. prototype. copy = function (targetBuffer, targetStart, sourceStart, sourceEnd) {payload. copy (buf, 2) // copy data, starting from 2 (third) bytes} else if (length <(1 <16) {buf = new Buffer (payload. length + 2 + 2); b2 |= 126; buf. writeUInt8 (b1, 0); buf. writeUInt8 (b2, 1); buf. writeUInt16BE (length, 2) payload. copy (buf, 4);} else {buf = new Buffer (payload. length + 2 + 8); b2 |= 127; buf. writeUInt8 (b1, 0); buf. writeUInt8 (b2, 1); buf. writeUInt32BE (0, 2) buf. writeUInt32BE (length, 6) payload. copy (buf, 10);} return buf ;}; /*** unmask ** @ param maskBytes mask data * @ param data payload * @ returns {Buffer} */var unmask = function (maskBytes, data) {var payload = new Buffer (data. length); for (var I = 0; I <data. length; I ++) {payload [I] = maskBytes [I % 4] ^ data [I];} return payload ;}; var KEY_SUFFIX = '258eafa5-E914-47DA-95CA-C5ABoDC85B11 '; /* equals to crypto. createHash ('sha1 '). update (key + 'key _ SUFFIX '). digest ('base64') **/var hashWebSocketKey = function (key) {"use strict"; var sha1 = crypto. createHash ('sha1'); sha1.update (key + KEY_SUFFIX, 'ascii '); return sha1.digest ('base64');}; exports. listen = function (port, host, connectionHandler) {"use strict"; var srv = http. createServer (function (req, res) {}); srv. on ('upgrade', function (req, socket, upgradeHead) {"use strict"; var ws = new WebSocketConnection (req, socket, upgradeHead ); connectionHandler (ws) ;}); srv. listen (port, host );};
Thank you for reading this article. I hope it will help you. Thank you for your support for this site!