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>


6 回复

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客户端,能够执行常见的操作如setgetdelete。希望这个简单的示例能帮助你更好地理解如何使用Node.js编写memcached客户端。


我擦编辑器处理错误了"result = thisthis.cmd+‘Handler’;"这里本来应该是result = this中括号this.cmd+'Handler’中括号();

汗,这怎么看~~

囧…现在可以看了, 我以为不能插入code, 原来可以的

红哇哇一篇啊~

Node.js 分享一个原创 Memcached 客户端

下面提供了一个简单的 Node.js 实现 Memcached 客户端的示例。该实现包括基本的命令(如 setgetadd 等)以及一些处理函数。

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];
    }
}

说明

  1. 连接和初始化:通过 net 模块建立到 Memcached 的 TCP 连接。
  2. 命令发送:支持 setgetaddreplacedeleteflush_allstats 等基本操作。
  3. 数据处理:根据 Memcached 返回的数据格式进行解析,返回给调用者。

希望这个实现对你有所帮助!

回到顶部