Nodejs 分享一个原创memcache客户端 原来可以插入code的 重新编辑了下
Nodejs 分享一个原创memcache客户端
原来可以插入code的 重新编辑了下
<pre><code>var net = require(‘net’);
exports.connect = function(port, host) { return new memcache(port, host); }
function memcache(port, host) { this.conn = null; this.port = port || 11211; this.host = host || ‘’; this.error = [‘ERROR’, ‘NOT_FOUND’, ‘CLIENT_ERROR’, ‘SERVER_ERROR’]; this.crlf = “ ”; this.queue = []; this.nextData = ‘’; this.init(); }
memcache.prototype = { init : function(){ this.buffer = new Buffer(’’); this.cmd = null; this.callback = null; this.receiveTimes = 0; this.headLength = 0; this.bodyLength = 0; if (this.nextData.length > 0) this.receive(new Buffer(this.nextData)); }, connect : function(callback){ if (this.conn) return callback.call(this); var conn = net.connect(this.port, this.host), self = this; conn.on(‘connect’, function(){ self.conn = conn; callback.call(self); }); conn.on(‘data’, function(data){ self.receive(data); }); conn.on(‘error’, function(e){ console.log(e); setTimeout(function(){ self.connect(callback); }, 10); }); }, fixKey : function(key) { return key.substr(0, 250).replace(/\s/g, ‘_’); }, query : function(data, callback, cmd) { var idx = data.indexOf(’ ‘), cmd = cmd || (idx == -1 ? data : data.substr(0, idx)).toLowerCase(); this.connect(function(){ this.queue.push({ cmd : cmd, callback : callback }); this.conn.write(data + this.crlf); }); }, send : function(cmd, key, value, callback, lifetime, flags) { if (typeof(callback) != ‘function’) { lifetime = callback; callback = null; } try { val = JSON.stringify(value); } catch(e) { try { val = value.toString(); } catch(e) { val = ‘’; } } var flags = flags || 0, lifetime = lifetime || 0, buffer = new Buffer(val), bufferLength = buffer.length || 0, query = [cmd, this.fixKey(key), flags, lifetime, bufferLength]; this.query(query.join(’ ') + this.crlf + val, callback); }, receive : function(data) { if (this.receiveTimes == 0) { var last = this.queue.shift(); this.cmd = last.cmd; this.callback = last.callback; } this.buffer = Buffer.concat([this.buffer, data]); this.receiveTimes++; result = thisthis.cmd+‘Handler’; if (result === null || result === undefined) return; try { this.callback(result); } catch(e) {} this.init(); }, add : function(key, value, callback, lifetime, flags) { this.send(‘add’, key, value, callback, lifetime, flags); }, set : function(key, value, callback, lifetime, flags) { this.send(‘set’, key, value, callback, lifetime, flags); }, replace : function(key, value, callback, lifetime, flags) { this.send(‘replace’, key, value, callback, lifetime, flags); }, get : function(key, callback) { this.query('get '+this.fixKey(key), callback); }, delete : function(key, callback) { this.query('delete '+this.fixKey(key), callback); }, flush : function(callback) { this.query(‘flush_all’, callback, ‘flush’); }, stats : function(callback) { this.query(‘stats’, callback); }, version : function(callback) { this.query(‘version’, callback); }, close : function(){ var self = this; if (this.queue.length == 0) { this.conn.end(); this.conn.destroy(); this.conn = null; } else { setTimeout(function(){ self.close(); }, 10); } }, getLine : function(data, line){ if (Buffer.isBuffer(data)) data = data.toString(); var line = line ? parseInt(line) : 0, data = data.split(" "); return data[line] ? data[line]+" " : false; }, storeHandler : function(){ var line = this.getLine(this.buffer); this.nextData = this.buffer.slice(new Buffer(line).length); if (line.toLowerCase().trim() == ‘stored’) { return true; } else { return false; } }, addHandler : function(){ return this.storeHandler(); }, setHandler : function(){ return this.storeHandler(); }, replaceHandler : function(){ return this.storeHandler(); }, getHandler : function(){ if (this.receiveTimes == 1) { //第一次开始接收数据 var line = this.getLine(this.buffer), header = line.split(/\s+/g); //不存在此KEY if (header[0].toLowerCase() == ‘end’) return false; this.headLength = new Buffer(line).length; this.bodyLength = parseInt(header[3]); } //实际buffer长度 var bufferLength = this.buffer.length, //buffer应有的长度 dataLength = this.headLength + this.bodyLength + ‘END’.length + 2 * this.crlf.length; if (bufferLength >= dataLength) { var body = this.buffer.slice(this.headLength, this.headLength + this.bodyLength).toString(); this.nextData = this.buffer.slice(dataLength).toString(); try { return JSON.parse(body); } catch(e) { return body; } } return null; }, deleteHandler : function(){ var line = this.getLine(this.buffer); this.nextData = this.buffer.slice(new Buffer(line).length); if (line.toLowerCase().trim() == ‘deleted’) { return true; } else { return false; } }, flushHandler : function(){ var line = this.getLine(this.buffer); this.nextData = this.buffer.slice(new Buffer(line).length); if (line.toLowerCase().trim() == ‘ok’) { return true; } else { return false; } }, statsHandler : function(){ var buffer = this.buffer.toString(), idx = buffer.indexOf(‘END’); if (idx != -1) { lines = buffer.trim().split(" "); var stats = {}; for(var i=0; i<lines.length-1; i++) { var line = lines[i].trim().split(/\s+/g); stats[line[1]] = line[2]; } this.nextData = new Buffer(buffer.substr(idx + ‘END’.length + this.crlf.length)); return stats; } return null; }, versionHandler : function(){ var line = this.getLine(this.buffer), header = line.split(/\s+/); this.nextData = this.buffer.slice(new Buffer(line).length); return header[1]; } }</code></pre>
Nodejs 分享一个原创memcache客户端
原来可以插入code的 重新编辑了下
在这个教程中,我们将创建一个简单的memcached客户端。该客户端将支持基本的操作,如设置、获取、删除键值对等。
var net = require('net');
exports.connect = function(port, host) {
return new MemcachedClient(port, host);
}
function MemcachedClient(port, host) {
this.conn = null;
this.port = port || 11211;
this.host = host || 'localhost';
this.error = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR'];
this.crlf = "\r\n";
this.queue = [];
this.nextData = '';
this.init();
}
MemcachedClient.prototype = {
init: function() {
this.buffer = new Buffer('');
this.cmd = null;
this.callback = null;
this.receiveTimes = 0;
this.headLength = 0;
this.bodyLength = 0;
if (this.nextData.length > 0) this.receive(new Buffer(this.nextData));
},
connect: function(callback) {
if (this.conn) return callback.call(this);
var conn = net.connect(this.port, this.host),
self = this;
conn.on('connect', function() {
self.conn = conn;
callback.call(self);
});
conn.on('data', function(data) {
self.receive(data);
});
conn.on('error', function(e) {
console.log(e);
setTimeout(function() {
self.connect(callback);
}, 10);
});
},
fixKey: function(key) {
return key.substr(0, 250).replace(/\s/g, '_');
},
query: function(data, callback, cmd) {
var idx = data.indexOf(' '),
cmd = cmd || (idx == -1 ? data : data.substr(0, idx)).toLowerCase();
this.connect(function() {
this.queue.push({
cmd: cmd,
callback: callback
});
this.conn.write(data + this.crlf);
});
},
send: function(cmd, key, value, callback, lifetime, flags) {
if (typeof(callback) !== 'function') {
lifetime = callback;
callback = null;
}
try {
value = JSON.stringify(value);
} catch (e) {
try {
value = value.toString();
} catch (e) {
value = '';
}
}
var flags = flags || 0,
lifetime = lifetime || 0,
buffer = new Buffer(value),
bufferLength = buffer.length || 0,
query = [cmd, this.fixKey(key), flags, lifetime, bufferLength];
this.query(query.join(' ') + this.crlf + value, callback);
},
receive: function(data) {
if (this.receiveTimes === 0) {
var last = this.queue.shift();
this.cmd = last.cmd;
this.callback = last.callback;
}
this.buffer = Buffer.concat([this.buffer, data]);
this.receiveTimes++;
var result = this[this.cmd + 'Handler']();
if (result === null || result === undefined) return;
try {
this.callback(result);
} catch (e) {}
this.init();
},
add: function(key, value, callback, lifetime, flags) {
this.send('add', key, value, callback, lifetime, flags);
},
set: function(key, value, callback, lifetime, flags) {
this.send('set', key, value, callback, lifetime, flags);
},
replace: function(key, value, callback, lifetime, flags) {
this.send('replace', key, value, callback, lifetime, flags);
},
get: function(key, callback) {
this.query('get ' + this.fixKey(key), callback);
},
delete: function(key, callback) {
this.query('delete ' + this.fixKey(key), callback);
},
flush: function(callback) {
this.query('flush_all', callback, 'flush');
},
stats: function(callback) {
this.query('stats', callback);
},
version: function(callback) {
this.query('version', callback);
},
close: function() {
var self = this;
if (this.queue.length === 0) {
this.conn.end();
this.conn.destroy();
this.conn = null;
} else {
setTimeout(function() {
self.close();
}, 10);
}
},
getLine: function(data, line) {
if (Buffer.isBuffer(data)) data = data.toString();
var line = line ? parseInt(line) : 0,
data = data.split("\n");
return data[line] ? data[line] + "\n" : false;
},
storeHandler: function() {
var line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'stored') {
return true;
} else {
return false;
}
},
addHandler: function() {
return this.storeHandler();
},
setHandler: function() {
return this.storeHandler();
},
replaceHandler: function() {
return this.storeHandler();
},
getHandler: function() {
if (this.receiveTimes === 1) {
var line = this.getLine(this.buffer),
header = line.split(/\s+/g);
if (header[0].toLowerCase() === 'end') return false;
this.headLength = new Buffer(line).length;
this.bodyLength = parseInt(header[3]);
}
var bufferLength = this.buffer.length,
dataLength = this.headLength + this.bodyLength + 'END'.length + 2 * this.crlf.length;
if (bufferLength >= dataLength) {
var body = this.buffer.slice(this.headLength, this.headLength + this.bodyLength).toString();
this.nextData = this.buffer.slice(dataLength).toString();
try {
return JSON.parse(body);
} catch (e) {
return body;
}
}
return null;
},
deleteHandler: function() {
var line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'deleted') {
return true;
} else {
return false;
}
},
flushHandler: function() {
var line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'ok') {
return true;
} else {
return false;
}
},
statsHandler: function() {
var buffer = this.buffer.toString(),
idx = buffer.indexOf('END');
if (idx !== -1) {
var lines = buffer.trim().split("\n");
var stats = {};
for (var i = 0; i < lines.length - 1; i++) {
var line = lines[i].trim().split(/\s+/g);
stats[line[1]] = line[2];
}
this.nextData = new Buffer(buffer.substr(idx + 'END'.length + this.crlf.length));
return stats;
}
return null;
},
versionHandler: function() {
var line = this.getLine(this.buffer),
header = line.split(/\s+/);
this.nextData = this.buffer.slice(new Buffer(line).length);
return header[1];
}
}
示例用法
var client = require('./memcached').connect(11211, 'localhost');
client.set('key', 'value', function(err, result) {
if (err) {
console.error('Set failed:', err);
} else {
console.log('Set successful:', result);
}
});
client.get('key', function(err, result) {
if (err) {
console.error('Get failed:', err);
} else {
console.log('Get successful:', result);
}
});
client.delete('key', function(err, result) {
if (err) {
console.error('Delete failed:', err);
} else {
console.log('Delete successful:', result);
}
});
总结
通过上述代码,我们实现了一个基本的memcached客户端,能够执行常见的操作如set
、get
和delete
。希望这个简单的示例能帮助你更好地理解如何使用Node.js编写memcached客户端。
我擦编辑器处理错误了"result = thisthis.cmd+‘Handler’;"这里本来应该是result = this中括号this.cmd+'Handler’中括号();
汗,这怎么看~~
囧…现在可以看了, 我以为不能插入code, 原来可以的
红哇哇一篇啊~
Node.js 分享一个原创 Memcached 客户端
下面提供了一个简单的 Node.js 实现 Memcached 客户端的示例。该实现包括基本的命令(如 set
、get
、add
等)以及一些处理函数。
const net = require('net');
exports.connect = function (port, host) {
return new MemcachedClient(port, host);
};
class MemcachedClient {
constructor(port, host) {
this.conn = null;
this.port = port || 11211;
this.host = host || 'localhost';
this.error = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR'];
this.crlf = '\r\n';
this.queue = [];
this.nextData = '';
this.init();
}
init() {
this.buffer = Buffer.alloc(0);
this.cmd = null;
this.callback = null;
this.receiveTimes = 0;
this.headLength = 0;
this.bodyLength = 0;
if (this.nextData.length > 0) this.receive(new Buffer(this.nextData));
}
connect(callback) {
if (this.conn) return callback.call(this);
const conn = net.connect(this.port, this.host);
const self = this;
conn.on('connect', () => {
self.conn = conn;
callback.call(self);
});
conn.on('data', (data) => {
self.receive(data);
});
conn.on('error', (e) => {
console.log(e);
setTimeout(() => {
self.connect(callback);
}, 10);
});
}
fixKey(key) {
return key.substr(0, 250).replace(/\s/g, '_');
}
query(data, callback, cmd) {
let idx = data.indexOf(' ');
cmd = cmd || (idx == -1 ? data : data.substr(0, idx)).toLowerCase();
this.connect(() => {
this.queue.push({
cmd: cmd,
callback: callback
});
this.conn.write(data + this.crlf);
});
}
send(cmd, key, value, callback, lifetime, flags) {
if (typeof callback !== 'function') {
lifetime = callback;
callback = null;
}
try {
value = JSON.stringify(value);
} catch (e) {
try {
value = value.toString();
} catch (e) {
value = '';
}
}
flags = flags || 0;
lifetime = lifetime || 0;
const buffer = Buffer.from(value);
const bufferLength = buffer.length || 0;
const query = [cmd, this.fixKey(key), flags, lifetime, bufferLength];
this.query(query.join(' ') + this.crlf + value, callback);
}
receive(data) {
if (this.receiveTimes === 0) {
const last = this.queue.shift();
this.cmd = last.cmd;
this.callback = last.callback;
}
this.buffer = Buffer.concat([this.buffer, data]);
this.receiveTimes++;
const result = this[this.cmd + 'Handler']();
if (result === null || result === undefined) return;
try {
this.callback(result);
} catch (e) {}
this.init();
}
add(key, value, callback, lifetime, flags) {
this.send('add', key, value, callback, lifetime, flags);
}
set(key, value, callback, lifetime, flags) {
this.send('set', key, value, callback, lifetime, flags);
}
replace(key, value, callback, lifetime, flags) {
this.send('replace', key, value, callback, lifetime, flags);
}
get(key, callback) {
this.query('get ' + this.fixKey(key), callback);
}
delete(key, callback) {
this.query('delete ' + this.fixKey(key), callback);
}
flush(callback) {
this.query('flush_all', callback, 'flush');
}
stats(callback) {
this.query('stats', callback);
}
version(callback) {
this.query('version', callback);
}
close() {
const self = this;
if (this.queue.length === 0) {
this.conn.end();
this.conn.destroy();
this.conn = null;
} else {
setTimeout(() => {
self.close();
}, 10);
}
}
getLine(data, line) {
if (Buffer.isBuffer(data)) data = data.toString();
line = line ? parseInt(line) : 0;
data = data.split('\n');
return data[line] ? data[line] + '\n' : false;
}
storeHandler() {
const line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'stored') {
return true;
} else {
return false;
}
}
addHandler() {
return this.storeHandler();
}
setHandler() {
return this.storeHandler();
}
replaceHandler() {
return this.storeHandler();
}
getHandler() {
if (this.receiveTimes === 1) {
const line = this.getLine(this.buffer);
const header = line.split(/\s+/g);
if (header[0].toLowerCase() === 'end') return false;
this.headLength = new Buffer(line).length;
this.bodyLength = parseInt(header[3]);
}
const bufferLength = this.buffer.length;
const dataLength = this.headLength + this.bodyLength + 'END'.length + 2 * this.crlf.length;
if (bufferLength >= dataLength) {
const body = this.buffer.slice(this.headLength, this.headLength + this.bodyLength).toString();
this.nextData = this.buffer.slice(dataLength).toString();
try {
return JSON.parse(body);
} catch (e) {
return body;
}
}
return null;
}
deleteHandler() {
const line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'deleted') {
return true;
} else {
return false;
}
}
flushHandler() {
const line = this.getLine(this.buffer);
this.nextData = this.buffer.slice(new Buffer(line).length);
if (line.toLowerCase().trim() === 'ok') {
return true;
} else {
return false;
}
}
statsHandler() {
const buffer = this.buffer.toString();
const idx = buffer.indexOf('END');
if (idx !== -1) {
const lines = buffer.trim().split('\n');
const stats = {};
for (let i = 0; i < lines.length - 1; i++) {
const line = lines[i].trim().split(/\s+/g);
stats[line[1]] = line[2];
}
this.nextData = new Buffer(buffer.substr(idx + 'END'.length + this.crlf.length));
return stats;
}
return null;
}
versionHandler() {
const line = this.getLine(this.buffer);
const header = line.split(/\s+/);
this.nextData = this.buffer.slice(new Buffer(line).length);
return header[1];
}
}
说明
- 连接和初始化:通过
net
模块建立到 Memcached 的 TCP 连接。 - 命令发送:支持
set
、get
、add
、replace
、delete
、flush_all
和stats
等基本操作。 - 数据处理:根据 Memcached 返回的数据格式进行解析,返回给调用者。
希望这个实现对你有所帮助!