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
- 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, 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
- 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!