Node js,变量范围.事件处理程序始终引用创建的第一个套接字



我正在尝试使用nodejs实现一个类似代理的应用程序。当客户端连接时,它将连接到2台服务器a和B。如果客户端发送"a",它将发送到服务器a,否则将发送到Server B。来自服务器a和服务器B的所有响应都将通过管道返回到客户端。我在这个网站上使用了liner模块https://strongloop.com/strongblog/practical-examples-of-the-new-node-js-streams-api/将传入的消息拆分为行。

如果只有一个客户端连接到服务器,我的代码就可以工作。但是,如果有多个客户端连接。其他客户端消息总是发送到为第一个客户端建立的服务器套接字。线性可读事件似乎总是引用创建的第一个服务器套接字,但我认为它应该是本地变量。

任何人都知道我的代码出了什么问题。

非常感谢。

var net = require('net');
var fs = require('fs');
var util = require('util');
var liner = require('./liner');
var server = net.createServer(function (clientSocket) { 
  console.log('client connected');
  var serverSocket2 = null;
  var serverSocket = net.connect({ host: '127.0.0.1', port: 9001 }, 
    function () {
      console.log('connected to server:' + serverSocket.remoteAddress);
      serverSocket2 = net.connect({ host: '127.0.0.1', port: 9002 }, 
        function () {
          console.log('connected to server ' + serverSocket2.remoteAddress);
          // pipe the client input to 2 server
          clientSocket.pipe(liner);
          // pipe server output to client socket
          serverSocket.pipe(clientSocket);
          serverSocket2.pipe(clientSocket);
      });
  });
  liner.on('readable', function () {
    var line;
    while (null !== (line = liner.read())) {
        if (line == "A") {
            serverSocket2.write(line + "rn");
        }
        if (line == "B") {
            serverSocket.write(line + "rn");
        }
    }
  });    
  clientSocket.on('end', function () {
    console.log('client disconnected');
    serverSocket.end();
    serverSocket2.end();
  });
});
server.listen(8123, function () { //'listening' listener
  console.log('server bound');
});

解决方案很简单:不要为所有连接使用共享全局liner实例。相反,将链接到的文章中的liner示例转换为从stream.Transform继承的构造函数,并使用该构造函数进行实例化。例如(使用链接文章中的代码):

var inherits = require('util').inherits;
var stream = require('stream');
function Liner() {
  if (!(this instanceof Liner))
    return new Liner();
  stream.Transform.call(this, { objectMode: true });
}
inherits(Liner, stream.Transform);
Liner.prototype._transform = function(chunk, encoding, done) {
  var data = chunk.toString();
  if (this._lastLineData)
    data = this._lastLineData + data;
  var lines = data.split('n');
  this._lastLineData = lines.splice(lines.length-1,1)[0];
  lines.forEach(this.push.bind(this));
  done();
};
Liner.prototype._flush = function (done) {
  if (this._lastLineData)
    this.push(this._lastLineData);
  this._lastLineData = null;
  done();
};
module.exports = Liner;

然后像这样使用:

var Liner = require('./liner');
var server = net.createServer(function(clientSocket) {
  var liner = new Liner();
  // ...
});

我还应该指出,像这样的"类"是不必要的,因为内置的readline模块也可以实现同样的功能。例如:

var readline = require('readline');
var net = require('net');
var server = net.createServer(function(clientSocket) {
  console.log('client connected');
  var rl;
  var serverSocket2 = null;
  var serverSocket = net.connect({ host: '127.0.0.1', port: 9001 }, 
    function () {
      console.log('connected to server:' + serverSocket.remoteAddress);
      serverSocket2 = net.connect({ host: '127.0.0.1', port: 9002 }, 
        function () {
          console.log('connected to server ' + serverSocket2.remoteAddress);
          // pipe the client input to 2 server
          rl = readline.createInterface({
            input: clientSocket
          });
          rl.on('line', lineHandler);
          // pipe server output to client socket
          serverSocket.pipe(clientSocket);
          serverSocket2.pipe(clientSocket);
        }
      );
    }
  );
  function lineHandler(line) {
    if (line === "A") {
      serverSocket2.write(line + "rn");
    } else if (line === "B") {
      serverSocket.write(line + "rn");
    }
  }
  clientSocket.on('end', function() {
    console.log('client disconnected');
    serverSocket.end();
    serverSocket2.end();
  });
});
server.listen(8123, function() {
  console.log('server bound');
});

最新更新