博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nodejs的redis协议解析器
阅读量:5760 次
发布时间:2019-06-18

本文共 6518 字,大约阅读时间需要 21 分钟。

  hot3.png

      最近用nodejs做项目,大规模的使用了redis,在windows下开发老是遇到各种问题,因为redis的协议解析器有问题,本来redis模块有两种协议解析的方式,一种是使用js实现的,另一种则是使用redis官方提供的hiredis的模块,当使用hiredis模块的时候当然一切正常,但是如果你是windows上的开发者,那么你没得选择,只能使用js版解析器,因为hiredis的模块在windows下安装不了,可是使用js版的解析器的时候就会出现各种问题,曾经改过几次这个js文件,但是还是没能把BUG完全修复完,于是一股脑直接重写了这个解析器,这次改动首先是修复各种协议上的问题,其中最大的区别是在效率的很大程度的提升,为什么这么说?因为原始的解析器方式是这样,如果一条完整的数据包有10K,此时因为网络原因只传输了8K,那么他必须先尝试解析,一旦发现包长度不够,就会等下次2K的数据来了之后再重新解析,意思就是说,之前解析的那8K的时间浪费了。而我改动的则是可以续解析,上次解析到哪里,下次收到数据包后,再接着上次解析的地方继续往下执行,节约了很多时间。简单介绍之后贴上代码吧,希望能对大家有帮助。

var events = require("events"),	util = require('../util');	exports.name = "fast javascript parser";exports.debug_mode = false;function Multi(n){	this.total = n;	this.offset = 0;	this.data = [];}Multi.prototype.push = function(d){	this.offset++;	this.data.push(d);};Multi.prototype.isFull = function(){	return (this.total == this.offset);};Multi.prototype.incr = function(){	this.offset++;};function ReplyParser(options){	this.name = exports.name;	this.options = options || { };	this._buffer			= null;	this._start				= -1;	this._offset			= 0;	this._encoding			= "utf-8";	this._debugMode			= options.debug_mode;	this._multi				= false;//多条数据?	this._multiData			= null;//多条数据成员	this._multiCursor		= null;//游标	this._data				= null;//单条数据内容	this._dataType			= 0;//单条数据类型	this._dataTotal			= 0;//单条数据总大小	this._dataOffset		= 0;//单条已接收的数据大小	this._parserFunc		= {		'+' : this._parseStatus,		'-' : this._parseError,		':' : this._parseInteger,		'$' : this._parseBulk,		'*' : this._parseMulti	};}util.inherits(ReplyParser, events.EventEmitter);exports.Parser = ReplyParser;ReplyParser.prototype.execute = function(buf){	this.append(buf);		while(this._offset < this._buffer.length)	{		if(!this._dataType){			if(this._buffer[this._offset] == 0x0d || 				this._buffer[this._offset] == 0x0a)			{//上次可能预留下来的结束标记				this._offset++;				continue;			}			this._dataType = this._buffer[this._offset];			this._offset++;		}				var type = String.fromCharCode(this._dataType);		if(this._parserFunc[type]){			var result = this._parserFunc[type].apply(this);			if(result){				if(this._multi){//多行数据					if(type == '*'){//当前处理的是头信息						if(this._multiCursor.total == -1){//多行数据异常							this._multiCursor.offset = -1;							this._multiCursor.data = null;						}					}else{//多行数据又处理一条						this._multiCursor.push(this._data);					}										//是否需要移动游标?					if(this._multiCursor.isFull() && 						(this._multiCursor != this._multiData))					{						this._multiData.push(this._multiCursor.data);						this._multiCursor = this._multiData;					}										//完整的多行数据处理完毕					if(this._multiData.isFull()){						this._sendReply(this._multiData.data);						this._reset2();						this._reset3();					}				}else if(type == '-'){//错误					this._sendError(this._data);					this._reset3();				}else{//单条数据					this._sendReply(this._data);					this._reset3();				}								//重置数据				this._reset();			}		}else{//非法的定义			break;		}	}};ReplyParser.prototype.append = function(buf){	//empty	if(!buf){		return ;	}		//first	if(this._buffer === null){		this._buffer = buf;		return ;	}		//append	this._buffer = Buffer.concat([this._buffer.slice(0), buf]);};//解析出错ReplyParser.prototype._parserError = function (message){	this.emit("error", message);};//发送错误ReplyParser.prototype._sendError = function (reply){	this.emit("reply error", reply);};//发送数据ReplyParser.prototype._sendReply = function (reply){	this.emit("reply", reply);};//重置数据ReplyParser.prototype._reset = function(){	this._start			= -1;	this._data			= null;	this._dataTotal		= 0;	this._dataOffset	= 0;	this._dataType		= 0;};//重置multi数据ReplyParser.prototype._reset2 = function(){	this._multi			= false;	this._multiData		= null;	this._multiCusror	= null;};//重置bufferReplyParser.prototype._reset3 = function(){	this._buffer		= this._buffer.slice(this._offset);	this._offset		= 0;};//只查找\r,忽略所后面的\nReplyParser.prototype._findEnd = function(){	var offset = this._offset;		while(offset < this._buffer.length)	{		if(this._buffer[offset] == 0x0d){			return offset;		}		offset++;	}		return false;};//解析状态ReplyParser.prototype._parseStatus = function(){	if(this._start === -1){		this._start = this._offset;	}		//查找结束标记	var end = this._findEnd();	if(end === false){		this._offset = this._buffer.length;		return false;	}		this._offset = end + 1;	this._data = this._buffer.toString(this._encoding, this._start, end);		return true;};//解析错误ReplyParser.prototype._parseError = function(){	if(this._start === -1){		this._start = this._offset;	}		var end = this._findEnd();	if(end === false){		this._offset = this._buffer.length;		return false;	}		this._offset = end + 1;	this._data = this._buffer.toString(this._encoding, this._start, end);		return true;	};//解析数字ReplyParser.prototype._parseInteger = function(){	if(this._start === -1){		this._start = this._offset;	}		var end = this._findEnd();	if(end === false){		this._offset = this._buffer.length;		return false;	}		this._offset = end + 1;	this._data = +(this._buffer.toString(this._encoding, this._start, end));		return true;};//解析单条数据ReplyParser.prototype._parseBulk = function(){	//读头信息	if(!this._dataTotal)	{		if(this._start === -1){			this._start = this._offset;		}				var end = this._findEnd();		if(end === false){			this._offset = this._buffer.length;			return false;		}				this._offset = end + 1;		this._dataOffset = 0;		this._dataTotal = +(this._buffer.toString(this._encoding, this._start, end));				//空数据		if(this._dataTotal == -1){			return true;		}	}		//缓冲区已空	if(this._offset >= this._buffer.length){		return false;	}		//准备开始读数据,\n要去掉	if((this._dataOffset == 0) && (this._buffer[this._offset] == 0x0a)){		this._offset++;	}		//分别计算出buffer中剩余的数据和本次需要的数据长度	var need = this._dataTotal - this._dataOffset;	var remain = this._buffer.length - this._offset;		//buffer中有足够的数据	if(remain >= need){		this._offset+= need;		this._data = this._buffer.toString(this._encoding, this._offset - this._dataTotal, this._offset);		return true;	}		//buffer中数据不足	this._offset = this._buffer.length;	this._dataOffset+= remain;		return false;};//解析多条数据ReplyParser.prototype._parseMulti = function(){	this._multi = true;	if(this._start === -1){		this._start = this._offset;	}	var end = this._findEnd();	if(end === false){		this._offset = this._buffer.length;		return false;	}		var n = +(this._buffer.toString(this._encoding, this._start, end));	this._offset = end + 1;		if(this._multiData === null){		this._multiData = new Multi(n);		this._multiCursor = this._multiData;	}else{		var m = new Multi(n);		this._multiCursor = m;	}		return true;};

转载于:https://my.oschina.net/scgywx/blog/158009

你可能感兴趣的文章
Cpp5 在堆中创建对象和引用类型
查看>>
添加Java文档注释
查看>>
Java8系列之重新认识HashMap
查看>>
软件工程网络15结对编程作业
查看>>
Python3批量爬取网页图片
查看>>
软工课总结和感想
查看>>
iphone-common-codes-ccteam源代码 CCEncoding.m
查看>>
pandas.concat
查看>>
使用OneNote2016发送博客
查看>>
ACL
查看>>
把一个List拆分为几个大小一样的List
查看>>
Educational Codeforces Round 33 (Rated for Div. 2) A. Chess For Three【模拟/逻辑推理】
查看>>
ios UIButton的点击与松开事件处理
查看>>
appache 在windows 中无法启动的测试
查看>>
内网渗透-代理(reGeorg)
查看>>
halcon算子翻译——access_channel
查看>>
Markdown
查看>>
解决hexo 谷歌站点地图抓取失败问题
查看>>
[Leetcode] Binary Tree Paths, Solution
查看>>
openssl基本原理 + 生成证书 + 使用实例
查看>>