UNPKG

eazy-pomelo

Version:
149 lines (123 loc) 4.14 kB
const util = require('util'); const EventEmitter = require('events').EventEmitter; const kcp = require('node-kcp'); const handler = require('./common/handler'); const Protocol = require('pomelo-protocol'); const Package = Protocol.Package; const Message = Protocol.Message; const ST_INITED = 0; const ST_WAIT_ACK = 1; const ST_WORKING = 2; const ST_CLOSED = 3; var output = function(data, size, context) { context.socket.send(data, 0, size, context.port, context.host); } var Socket = function(id, socket, address, port, opts) { EventEmitter.call(this); let self = this; this.id = id; this.socket = socket; this.host = address; this.port = port; this.remoteAddress = { ip: this.host, port: this.port }; this.opts = opts; let conv = opts.conv || 123; this.kcpobj = new kcp.KCP(conv, self); if (!!opts) { let nodelay = opts.nodelay || 0; //是否启用 nodelay模式,0不启用;1启用。 let interval = opts.interval || 100; //协议内部工作的 interval,单位毫秒,比如 10ms或者 20ms let resend = opts.resend || 0; //快速重传模式,默认0关闭,可以设置2(2次ACK跨越将会直接重传) let nc = opts.nc || 0; //是否关闭流控,默认是0代表不关闭,1代表关闭。 this.kcpobj.nodelay(nodelay, interval, resend, nc); //普通模式: nodelay(kcp, 0, 40, 0, 0); 极速模式: nodelay(kcp, 1, 10, 2, 1); let sndwnd = opts.sndwnd || 32; //该调用将会设置协议的最大发送窗口和最大接收窗口大小, 单位是包 let rcvwnd = opts.rcvwnd || sndwnd; this.kcpobj.wndsize(sndwnd, rcvwnd); let mtu = opts.mtu || 1400; //降低 mtu 到 470,同样数据虽然会发更多的包,但是小包在路由层优先级更高 this.kcpobj.setmtu(mtu); } this.kcpobj.output(output); this.on('input', function(msg){ this.kcpobj.input(msg); let data = this.kcpobj.recv(); if (!!data) { data = Package.decode(data); if (Array.isArray(data)) { for (let p in data) { handler(self, data[p]); } } else { handler(self, data); } } }); this.on('end', function(msg){ if (!!msg) { self.socket.write(msg); self.state = ST_CLOSED; self.emit('end'); } }); this.check(); this.state = ST_INITED; } util.inherits(Socket, EventEmitter); module.exports = Socket; Socket.prototype.check = function() { let self = this; if(this.state == ST_CLOSED){ return; } let now = Date.now(); this.kcpobj.update(now); setTimeout(function(){ self.check(); }, this.kcpobj.check(now)); } Socket.prototype.send = function(msg) { if (this.state != ST_WORKING) { return; } if (msg instanceof String) { msg = new Buffer(msg); } else if (!(msg instanceof Buffer)) { msg = new Buffer(JSON.stringify(msg)); } this.sendRaw(Package.encode(Package.TYPE_DATA, msg)); } Socket.prototype.sendRaw = function(msg) { this.kcpobj.send(msg); this.kcpobj.flush(); } Socket.prototype.sendForce = function(msg) { if (this.state == ST_CLOSED) { return; } this.sendRaw(msg); } Socket.prototype.sendBatch = function(msgs) { if (this.state != ST_WORKING) { return; } var rs = []; for (var i = 0; i < msgs.length; i++) { rs.push(Package.encode(Package.TYPE_DATA, msgs[i])); } this.sendRaw(Buffer.concat(rs)); } Socket.prototype.handshakeResponse = function(resp) { if(this.state !== ST_INITED) { return; } this.sendRaw(resp); this.state = ST_WAIT_ACK; } Socket.prototype.disconnect = function(msg) { if (this.state == ST_CLOSED) { return; } this.state = ST_CLOSED; this.emit('disconnect', 'connection disconnected'); }