WebSocket protocol detailed and simple example code _ basics

Source: Internet
Author: User
Tags base64 emit sha1

The WebSocket agreement is detailed

For the WebSocket agreement, please refer to the other articles.

WebSocket keywords

HTML5 protocol, real-time, Full-duplex communication, long connection

The benefits of WebSocket than 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, feedback the securities information to the client faithfully (this is critical), and real-time weather data is more flexible than the HTTP request response mode
    3. Lighter protocol headers to reduce data transfer volume

Data frame format

The following figure is a manually crafted data frame format


/**
 * fin  |masked    |      |
 * SRV1 |  Length   |      |
 * srv2 |  (7bit   |mask data   |payload
 * srv3 |   7+2 bytes  | 4 bytes    | real data
 opcode |   7+64 byte |      |
 * (4bit) * *
 

Make the following note:

1. First 8 bit (one byte)
-fin: Whether the data is sent to completion for 1 send completed for 0 send not finished.
-srv1,srv2,srv3: reserved for later use
-opcode: data type opcode, 4bit indicates that
Text:1, string of text type
Binary:2, binary data, usually used to save pictures
Close:8, closes 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 opcode TEXT String * BINARY binary data is commonly used to save photos * Ping,pong for heartbeat detection * Close closes the connected data frame (there are many close-connected code 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 head/socket.write (' http/1.1 Web socket Protocol handshake \ r \ n ' + ' upgrade:websocket\r\n ' + "Co

  nnection: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);
  /* Send data function * */WebSocketConnection.prototype.send = function (obj) {"Use strict";
  var opcode;
  VAR payload; if (Buffer.isbuffer (obj)) {opcode = opcodes.
    BINARY;
  payload = obj; else if (typeof obj) {opcode = opcodes.
    TEXT;
  Creating a UTF8 encoding can be encoded as a string payload = new Buffer (obj, ' utf8 '); else {throw new Error (' Cannot send object.
  Must be string of Buffer ');
} this._dosend (opcode, payload);
};
  /* Close 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);
    Buffer.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 data frame before 8bit var fin = b1 & 0x80; If 0x80, the flag transfer end var opcode = B1 & 0x0f;//intercepts the four-bit var b2 = buf.readuint8 (1) of the first byte;//Read the second byte of the data frame var mask = B2 ; 0x80;//to determine if there is a mask, the client must have var length = B2 | 0x7f;//Gets the length property is also a data true value of less than 126 data length if (length >) {if (Buf.length < 8) {return;//If greater than 125 and the number of bytes is less than 8, the  Obviously irregular requirements}} if (length = = 126) {//Get a value of 126, indicating that the latter two bytes is used to indicate length = BUF.READUINT16BE (2);//Read 16bit value IDX 
    + = 2;//+2} else if (length = = 127) {//Get a value of 126, indicating that the following 8 bytes are used to represent the data length var highbits = Buf.readuint32be (2);//(1/0) 1111111 if (highbits!= 0) {this.close (1009, "");//1009 close code, stating that the data is too large} length = Buf.readuint32be (6);//from sixth to tenth bytes
  The true stored data length idx + 8;
  } if (Buf.length < IDX + 4 + length) {//not longer than 4 for mask byte number return; var maskbytes = buf.slice (idx, IDX + 4);//Get Mask Data idx+ + 4;//pointer move forward to real data segment var payload = Buf.slice (idx, idx + length);  Payload = unmask (maskbytes, payload),//decoding real data this._handleframe (opcode, payload);//processing opcode This.buffer = buf.slice (idx +
length);//cache buffer return true;

};  /** * for different operating codes for different processing * @param operation code * @param data/websocketconnection.prototype._handleframe = function (opcode, buffer)
  {"Use strict";
  VAR payload; switch (opcode) {case opcodes. Text:payload = buffer.tostring (' UTF8 '); if the text needs to be translated into UTF8 encoding this.emit (' data ', opcode, payload);//buffer.tostri
    Ng () default UTF8 here is deliberately directed by the break; Case Opcodes.
      BINARY://binary file direct delivery payload = buffer;
      This.emit (' data ', opcode, payload);
    Break Case Opcodes. ping://sends Ping to do the response This._dosend (opcodes.
      PING, buffer);
    Break Case Opcodes.
    PONG://do not handle break; Case Opcodes. Close://close has a lot of shutdown code let code, reason;//is used to get off code and shutdown reason if (buffer.length >= 2) {code = Buffer.readuin
        T16BE (0); Reason = Buffer.tostRing (' UTF8 ', 2);
      } this.close (code, reason);
      This.emit (' Close ', Code, Reason);
    Break
  Default:this.close (1002, ' unknown opcode ');

}
}; /** * The function that actually sends the data * @param opcode operation code * @param payload Data * @private/websocketconnection.prototype._dosend = Functio
  n (opcode, payload) {"Use strict";

This.socket.write (encodemessage (opcode, payload));//encoded directly through the socket to send}; /** * encoded 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 before 8bit buf.writeuint8 (B2, 1),//read 8―15bit//buffer.prototype.copy = fun Ction (Targetbuffer, Targetstart, Sourcestart, sourceend) {payload.copy (buf, 2)//copy data, starting with 2 (third) bytes} else if (length < (1 <<)) {buf = newBuffer (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;

}; /** * Mask * @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, I hope to help you, thank you for your support for this site!

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.