Detailed explanation of Websocket protocol and simple example code
Websocket protocol detailed explanation
For what the websocket protocol is used for, please refer to other articles.
WebSocket keywords
HTML5 protocol, real-time, full-duplex communication, long connection
Benefits of WebSocket over traditional Http
1. The client and server only establish one TCP connection, which can use fewer connections
2. The WebSocket server can push data to the client, such as real-time feedback of securities information to the client (this is very critical), real-time weather data, which is more flexible than the http request response mode
3. Lighter protocol headers , reduce the amount of data transmission
Data frame format
The picture below shows the hand-crafted data frame format
/** * fin |masked | | * srv1 | length | | * srv2 | (7bit |mask数据 |payload * srv3 | 7+2字节 | 4字节 |真实数据 opcode | 7+64字节 | | *(4bit) */
as follows:
1. The first 8 bits (one byte)
—fin: Whether the data transmission is completed , is 1 for sending completed and 0 for incomplete sending.
—srv1, srv2, srv3: reserved for later use
—opcode: data type opcode, 4-bit representation, where
TEXT: 1, text type string
BINARY:
2. Binary data, usually used to save pictures
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'); /** * 数据类型操作码 TEXT 字符串 * BINARY 二进制数据 常用来保存照片 * PING,PONG 用作心跳检测 * CLOSE 关闭连接的数据帧 (有很多关闭连接的代码 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']); /** * 写头 */ 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'); /** * 接收数据 */ 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连接继承事件 util.inherits(WebSocketConnection, events.EventEmitter); /* 发送数据函数 * */ 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; //创造一个utf8的编码 可以被编码为字符串 payload = new Buffer(obj, 'utf8'); } else { throw new Error('cannot send object.Must be string of Buffer'); } this._doSend(opcode, payload); }; /* 关闭连接函数 * */ 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); //读取数据帧的前8bit var fin = b1 & 0x80; //如果为0x80,则标志传输结束 var opcode = b1 & 0x0f;//截取第一个字节的后四位 var b2 = buf.readUInt8(1);//读取数据帧第二个字节 var mask = b2 & 0x80;//判断是否有掩码,客户端必须要有 var length = b2 | 0x7f;//获取length属性 也是小于126数据长度的数据真实值 if (length > 125) { if (buf.length < 8) { return;//如果大于125,而字节数小于8,则显然不合规范要求 } } if (length === 126) {//获取的值为126 ,表示后两个字节用于表示数据长度 length = buf.readUInt16BE(2);//读取16bit的值 idx += 2;//+2 } else if (length === 127) {//获取的值为126 ,表示后8个字节用于表示数据长度 var highBits = buf.readUInt32BE(2);//(1/0)1111111 if (highBits != 0) { this.close(1009, "");//1009关闭代码,说明数据太大 } length = buf.readUInt32BE(6);//从第六到第十个字节为真实存放的数据长度 idx += 8; } if (buf.length < idx + 4 + length) {//不够长 4为掩码字节数 return; } var maskBytes = buf.slice(idx, idx + 4);//获取掩码数据 idx += 4;//指针前移到真实数据段 var payload = buf.slice(idx, idx + length); payload = unmask(maskBytes, payload);//解码真实数据 this._handleFrame(opcode, payload);//处理操作码 this.buffer = buf.slice(idx + length);//缓存buffer return true; }; /** * 针对不同操作码进行不同处理 * @param 操作码 * @param 数据 */ WebSocketConnection.prototype._handleFrame = function (opcode, buffer) { "use strict"; var payload; switch (opcode) { case opcodes.TEXT: payload = buffer.toString('utf8');//如果是文本需要转化为utf8的编码 this.emit('data', opcode, payload);//Buffer.toString()默认utf8 这里是故意指示的 break; case opcodes.BINARY: //二进制文件直接交付 payload = buffer; this.emit('data', opcode, payload); break; case opcodes.PING://发送ping做响应 this._doSend(opcodes.PING, buffer); break; case opcodes.PONG: //不做处理 break; case opcodes.CLOSE://close有很多关闭码 let code, reason;//用于获取关闭码和关闭原因 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'); } }; /** * 实际发送数据的函数 * @param opcode 操作码 * @param payload 数据 * @private */ WebSocketConnection.prototype._doSend = function (opcode, payload) { "use strict"; this.socket.write(encodeMessage(opcode, payload));//编码后直接通过socket发送 }; /** * 编码数据 * @param opcode 操作码 * @param payload 数据 * @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);//读前8bit buf.writeUInt8(b2, 1);//读8―15bit //Buffer.prototype.copy = function(targetBuffer, targetStart, sourceStart, sourceEnd) { payload.copy(buf, 2)//复制数据,从2(第三)字节开始 } 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; }; /** * 解掩码 * @param maskBytes 掩码数据 * @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); };

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



How to use WebSocket and JavaScript to implement an online speech recognition system Introduction: With the continuous development of technology, speech recognition technology has become an important part of the field of artificial intelligence. The online speech recognition system based on WebSocket and JavaScript has the characteristics of low latency, real-time and cross-platform, and has become a widely used solution. This article will introduce how to use WebSocket and JavaScript to implement an online speech recognition system.

With the continuous development of Internet technology, real-time video streaming has become an important application in the Internet field. To achieve real-time video streaming, the key technologies include WebSocket and Java. This article will introduce how to use WebSocket and Java to implement real-time video streaming playback, and provide relevant code examples. 1. What is WebSocket? WebSocket is a protocol for full-duplex communication on a single TCP connection. It is used on the Web

With the continuous development of Internet technology, real-time communication has become an indispensable part of daily life. Efficient, low-latency real-time communication can be achieved using WebSockets technology, and PHP, as one of the most widely used development languages in the Internet field, also provides corresponding WebSocket support. This article will introduce how to use PHP and WebSocket to achieve real-time communication, and provide specific code examples. 1. What is WebSocket? WebSocket is a single

The combination of golangWebSocket and JSON: realizing data transmission and parsing In modern Web development, real-time data transmission is becoming more and more important. WebSocket is a protocol used to achieve two-way communication. Unlike the traditional HTTP request-response model, WebSocket allows the server to actively push data to the client. JSON (JavaScriptObjectNotation) is a lightweight format for data exchange that is concise and easy to read.

WebSocket and JavaScript: Key technologies for realizing real-time monitoring systems Introduction: With the rapid development of Internet technology, real-time monitoring systems have been widely used in various fields. One of the key technologies to achieve real-time monitoring is the combination of WebSocket and JavaScript. This article will introduce the application of WebSocket and JavaScript in real-time monitoring systems, give code examples, and explain their implementation principles in detail. 1. WebSocket technology

PHP and WebSocket: Best Practice Methods for Real-Time Data Transfer Introduction: In web application development, real-time data transfer is a very important technical requirement. The traditional HTTP protocol is a request-response model protocol and cannot effectively achieve real-time data transmission. In order to meet the needs of real-time data transmission, the WebSocket protocol came into being. WebSocket is a full-duplex communication protocol that provides a way to communicate full-duplex over a single TCP connection. Compared to H

How does JavaWebsocket implement online whiteboard function? In the modern Internet era, people are paying more and more attention to the experience of real-time collaboration and interaction. Online whiteboard is a function implemented based on Websocket. It enables multiple users to collaborate in real-time to edit the same drawing board and complete operations such as drawing and annotation. It provides a convenient solution for online education, remote meetings, team collaboration and other scenarios. 1. Technical background WebSocket is a new protocol provided by HTML5. It implements

In this article, we will compare Server Sent Events (SSE) and WebSockets, both of which are reliable methods for delivering data. We will analyze them in eight aspects, including communication direction, underlying protocol, security, ease of use, performance, message structure, ease of use, and testing tools. A comparison of these aspects is summarized as follows: Category Server Sent Event (SSE) WebSocket Communication Direction Unidirectional Bidirectional Underlying Protocol HTTP WebSocket Protocol Security Same as HTTP Existing security vulnerabilities Ease of use Setup Simple setup Complex performance Fast message sending speed Affected by message processing and connection management Message structure Plain text or binary Ease of use Widely available Helpful for WebSocket integration
