Websocket protocol details and simple instance code, websocket details examples

Source: Internet
Author: User
Tags emit

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

  1. Only one TCP connection is established between the client and the server, and fewer connections can be used.
  2. 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.
  3. 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!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.