简体   繁体   中英

Custom TCP-Protocol on node.js

how i can implement a custom protocol on a Node.js NET-Client?

The problem is:

I want to connect to a server. That server has an simple protocol. Each packet has a length-prefix, it means the first byte say how long the packet is.

How i can implement that? How i can read for example the first byte to get the packet-length to read the other stuff?

var net         = require('net');
var client      = new net.Socket();

client.connect(2204, 'myexampledomain.com', function() {
    console.log('Connecting...', protocol);
});

client.on('data', function(data) {

    console.log('DATA: ' + data);
});

client.on('end', function() {
    console.log('end');
});

client.on('timeout', function() {
    console.log('timeout');
});

client.on('drain', function() {
    console.log('drain');
});

client.on('error', function() {
    console.log('error');
});

client.on('close', function() {
    console.log('Connection closed');
});

client.on('connect', function() {
    console.log('Connect');
    client.write("Hello World");
});

You'll have to maintain an internal buffer holding received data and check if it has length bytes before slicing the packet from it. The buffer must be concatenated with received data until it has length bytes and emptied on receiving a full packet. This can be better handled using a Transform stream.

This is what I used in my json-rpc implementation. Each JSON packet is lengthPrefixed . The message doesn't have to be JSON – you can replace the call to this.push(JSON.parse(json.toString())); .

var Transform = require('stream').Transform;

function JsonTransformer(options) {
    if (!(this instanceof JsonTransformer)) {
        return new JsonTransformer(options);
    }
    Transform.call(this, {
        objectMode: true
    });
/*Transform.call(this);
    this._readableState.objectMode = false;
    this._writableState.objectMode = true;*/
    this.buffer = new Buffer(0);
    this.lengthPrefix = options.lengthPrefix || 2;
    this._readBytes = {
        1: 'readUInt8',
        2: 'readUInt16BE',
        4: 'readUInt32BE'
    }[this.lengthPrefix];
}

JsonTransformer.prototype = Object.create(Transform.prototype, {
    constructor: {
        value: JsonTransformer,
        enumerable: false,
        writable: false
    }
});


function transform() {
    var buffer = this.buffer,
        lengthPrefix = this.lengthPrefix;
    if (buffer.length > lengthPrefix) {
        this.bytes = buffer[this._readBytes](0);
        if (buffer.length >= this.bytes + lengthPrefix) {
            var json = buffer.slice(lengthPrefix, this.bytes + lengthPrefix);
            this.buffer = buffer.slice(this.bytes + lengthPrefix);
            try {
                this.push(JSON.parse(json.toString()));
            } catch(err) {
                this.emit('parse error', err);
            }

            transform.call(this);
        }
    }
}

JsonTransformer.prototype._transform = function(chunk, encoding, next) {
    this.buffer = Buffer.concat([this.buffer, chunk]);
    transform.call(this);
    next();
}

JsonTransformer.prototype._flush = function() {
    console.log('Flushed...');
}

var json = new JsonTransformer({lengthPrefix: 2});
var socket = require('net').createServer(function (socket) {
    socket.pipe(json).on('data', console.log);
});
socket.listen(3000);


module.exports = JsonTransformer;

json-transformer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM