UNPKG

@lvgithub/stick

Version:

The solution of sticky package problem of TCP for Node.Js !

314 lines (270 loc) 11.1 kB
'use strict'; const EventEmitter = require('events').EventEmitter; const Assert = require('assert'); const StackBuffer = function (bufferSize) { const bufferLength = bufferSize; const _event = new EventEmitter(); let _dataWritePosition = 0;//数据存储起始位置 let _dataReadPosition = 0;//数据存储结束位置 let _dataHeadLen = 2;//数据包头长度 let _dataLen = 0;//已经接收数据的长度 let _bufferLength = bufferLength || 512; //buffer默认长度 let _buffer = Buffer.alloc(bufferLength || _bufferLength);//申请内存 let _readIntMethod = 'readInt16BE'; let _writeIntMethod = 'writeInt16BE'; this.readIntMethod = _readIntMethod; this.writeIntMethod = _writeIntMethod; this.dataHeadLen = _dataHeadLen; /** * 设置大端接收 * type:16 包头长度为2,short类型 * type:32 包头长度为4,int类型 */ this.setReadIntBE = function (type) { type = Number(type); const isValid = (type === 16 || type === 32); Assert(isValid, ' invalid type(must be 16 or 32)'); _readIntMethod = 'readInt' + type + 'BE'; _writeIntMethod = 'writeInt' + type + 'BE'; _dataHeadLen = (type === 16) ? 2 : 4; this.readIntMethod = _readIntMethod; this.writeIntMethod = _writeIntMethod; this.dataHeadLen = _dataHeadLen; return this; }; /** * 设置小端接收 * type:16 包头长度为2,short类型 * type:32 包头长度为4,int类型 */ this.setReadIntLE = function (type) { type = Number(type); const isValid = (type === 16 || type === 32); Assert(isValid, ' invalid type(must be 16 or 32)'); _readIntMethod = 'readInt' + type + 'LE'; _writeIntMethod = 'writeInt' + type + 'LE'; _dataHeadLen = (type === 16) ? 2 : 4; this.readIntMethod = _readIntMethod; this.writeIntMethod = _writeIntMethod; this.dataHeadLen = _dataHeadLen; return this; }; this.setMaxBodyLen = (length, isLE = false) => { if (length !== 2 && length !== 4) { throw new Error('length must is number 2 or 4'); } if (!isLE) { this.setReadIntBE(length * 8); } else { this.setReadIntLE(length * 8); } return this; }; // 数据包接收完整后触发事件 this.onData = function (callback) { _event.on('data', callback); }; // 只返回body this.onBody = function (callback) { _event.on('data', data => { const headLen = _dataHeadLen; const head = Buffer.alloc(headLen); data.copy(head, 0, 0, headLen); const dataLen = head[_readIntMethod](); const body = Buffer.alloc(dataLen); data.copy(body, 0, headLen, headLen + dataLen); callback(body); }); }; // 数据包错误触发事件 this.onError = function (callback) { _event.on('error', callback); }; // 往buffer填入数据 this.putData = function (data) { // console.log('收到数据'); if (data === undefined) { return; } //要拷贝数据的起始位置 let dataSatrt = 0; // 要拷贝数据的结束位置 let dataLength = data.length; // 缓存剩余可用空间 let availableLen = this.getAvailableLen(); // buffer剩余空间不足够存储本次数据 if (availableLen < dataLength) { // 以512字节为基数扩展Buffer空间 let exLength = Math.ceil((_dataLen + dataLength) / 512) * 512; let tempBuffer = Buffer.alloc(exLength); //_buffer.copy(tempBuffer); _bufferLength = exLength; // 数据存储进行了循环利用空间,需要进行重新打包 // 数据存储在buffer的尾部+头部的顺序 if (_dataWritePosition < _dataReadPosition) { let dataTailLen = _bufferLength - _dataReadPosition; _buffer.copy(tempBuffer, 0, _dataReadPosition, _dataReadPosition + dataTailLen); _buffer.copy(tempBuffer, dataTailLen, 0, _dataWritePosition); } // 数据是按照顺序进行的完整存储 else { _buffer.copy(tempBuffer, 0, _dataReadPosition, _dataWritePosition); } _buffer = tempBuffer; tempBuffer = null; _dataReadPosition = 0; _dataWritePosition = _dataLen; data.copy(_buffer, _dataWritePosition, dataSatrt, dataSatrt + dataLength); _dataLen += dataLength; _dataWritePosition += dataLength; } // 数据会冲破buffer尾部 else if (_dataWritePosition + dataLength > _bufferLength) { /* 分两次存储到buffer: * 1、存储在原数据尾部 * 2、存储在原数据头部 */ // buffer尾部剩余空间的长度 let bufferTailLength = _bufferLength - _dataWritePosition; if (bufferTailLength < 0) { console.log('程序有漏洞,bufferTailLength < 0 '); } // 数据尾部位置 let dataEndPosition = dataSatrt + bufferTailLength; data.copy(_buffer, _dataWritePosition, dataSatrt, dataEndPosition); _dataWritePosition = 0; dataSatrt = dataEndPosition; // data剩余未拷贝进缓存的长度 let unDataCopyLen = dataLength - bufferTailLength; data.copy(_buffer, _dataWritePosition, dataSatrt, dataSatrt + unDataCopyLen); // 记录数据长度 _dataLen = _dataLen + dataLength; // 记录buffer可写位置 _dataWritePosition = _dataWritePosition + unDataCopyLen; } // 剩余空间足够存储数据 else { // 拷贝数据到buffer data.copy(_buffer, _dataWritePosition, dataSatrt, dataSatrt + dataLength); if (_dataWritePosition > _bufferLength) { console.log('程序有漏洞'); } // 记录数据长度 _dataLen = _dataLen + dataLength; // 记录buffer可写位置 _dataWritePosition = _dataWritePosition + dataLength; } // 读取数据 getData(); }; // 往buffer填入消息 this.putMsg = function (msg) { const bodyBuf = Buffer.from(msg); const headBuf = Buffer.alloc(_dataHeadLen); headBuf[_writeIntMethod](bodyBuf.byteLength, 0); this.putData(headBuf); this.putData(bodyBuf); }; this.putBody = body => { this.putMsg(body); }; // 往buffer填入消息 this.publish = function (msg) { const bodyBuf = Buffer.from(msg); const headBuf = Buffer.alloc(_dataHeadLen); headBuf[_writeIntMethod](bodyBuf.byteLength, 0); const msgBuf = Buffer.alloc(headBuf.length + bodyBuf.length); headBuf.copy(msgBuf, 0, 0, headBuf.length); bodyBuf.copy(msgBuf, headBuf.length, 0, bodyBuf.length); return msgBuf; }; this.makeData = this.publish; // 获取数据 function getData() { // eslint-disable-next-line no-constant-condition while (true) { // 没有数据可读,不够解析出包头 if (getDataLen() <= _dataHeadLen) { break; } // 解析包头长度 // 尾部最后剩余可读字节长度 let buffLastCanReadLen = _bufferLength - _dataReadPosition; let dataLen = 0; let headBuffer = Buffer.alloc(_dataHeadLen); // 数据包为分段存储,不能直接解析出包头 if (buffLastCanReadLen < _dataHeadLen) { // 取出第一部分头部字节 _buffer.copy(headBuffer, 0, _dataReadPosition, _buffer.length); // 取出第二部分头部字节 let unReadHeadLen = _dataHeadLen - buffLastCanReadLen; _buffer.copy(headBuffer, buffLastCanReadLen, 0, unReadHeadLen); // 默认大端接收数据 dataLen = headBuffer[_readIntMethod]() + _dataHeadLen; } else { _buffer.copy(headBuffer, 0, _dataReadPosition, _dataReadPosition + _dataHeadLen); dataLen = headBuffer[_readIntMethod](); dataLen += _dataHeadLen; } // 数据长度不够读取,直接返回 if (getDataLen() < dataLen) { break; } // 数据够读,读取数据包 else { let readData = Buffer.alloc(dataLen); // 数据是分段存储,需要分两次读取 if (_bufferLength - _dataReadPosition < dataLen) { let firstPartLen = _bufferLength - _dataReadPosition; // 读取第一部分,直接到字符尾部的数据 _buffer.copy(readData, 0, _dataReadPosition, firstPartLen + _dataReadPosition); // 读取第二部分,存储在开头的数据 let secondPartLen = dataLen - firstPartLen; _buffer.copy(readData, firstPartLen, 0, secondPartLen); _dataReadPosition = secondPartLen; } // 直接读取数据 else { _buffer.copy(readData, 0, _dataReadPosition, _dataReadPosition + dataLen); _dataReadPosition += dataLen; } try { // console.log('emit data'); _event.emit('data', readData); _dataLen -= readData.length; // 已经读取完所有数据 if (_dataReadPosition === _dataWritePosition) { break; } } catch (e) { _event.emit('error', e); } } } } // 获取缓存数据长度 function getDataLen() { let dataLen = 0; // 缓存全满 if (_dataLen === _bufferLength && _dataWritePosition >= _dataReadPosition) { dataLen = _bufferLength; } // 缓存全部数据读空 else if (_dataWritePosition >= _dataReadPosition) { dataLen = _dataWritePosition - _dataReadPosition; } else { dataLen = _bufferLength - _dataReadPosition + _dataWritePosition; } if (dataLen !== _dataLen) { console.log('程序有漏洞,dataLen长度不合法'); } return dataLen; } // 获取buffer可用的空间长度 this.getAvailableLen = function () { return _bufferLength - _dataLen; }; }; module.exports = exports = StackBuffer;