Node 如何将之前的同步TCP改成异步
发布于 9 年前 作者 DMIAOCHEN 4598 次浏览 最后一次编辑是 8 年前 来自 问答

是这样的, 我想把本来.Net的程序移植到Node上来, 现在碰到了一个问题, 以前通信都是同步的所以没什么问题, 但是现在异步了之后想了好久不知道怎么解决,希望大家能帮忙给点意见~~ 先假设整个系统分成三个部分,Server(后端处理器)、WebServer(网页后台以前.Net写的)、Web(前端网页)。 Sevrer和WebServer之间是通过TCP来通信的(之前一直是同步的),WebServer和Web之间用ajax通信,现在Web向WebServer请求一个值V, WebServer收到请求后, 再向Server发一条请求命令,然后WebServer收到Server返回值V, 再将V返回给Web端。 以前是同步的没什么问题, 都是等待返回, 但是现在如果在Node上,那我WebServer向Server发出请求后就返回了,这时候其实还没有收到Server的回复, 就返回给Web了。我也想过用回调的方式,如下的代码,当发送命令给Server端即调用下面的sendDmitc的时候都带一个回调函数(callback),然后在socket的data事件中会调用callback,这样处理一次连接是没什么问题, 但是如果第一次会话(callback1)还没有返回,第二次会话(callback2)就来了, 那么callback不就被设置成callback2了么, 一直想不到什么办法来处理这个问题, 希望大家帮忙给点意见, 谢谢~~

var net = require("net");
var parseString = require('xml2js').parseString;
var uuid = require("node-uuid");
var iccModels = require('./iccModels.js');
var Q = require('q');


var idleFunc = function (data, err) {
    console.log('idle handle: ' + data);
};


var serverConnector = function (host, port) {
    var self = this;
    this.commandList = [];
    this.host = host;
    this.port = port;
	//Socket接收完数据后都会调用这个回调
    this.recvCallback = idleFunc;
    
    this._bConnect = false;
    this._session = new net.Socket();
    
    this._session.setKeepAlive(true);

    this._session.on('data', function (data) {
        var err = '';

        // 将Buffer的内容解析出来
        var iccData = new iccModels.ICCData();

        // 先提取前面两个字节, 表示类型
        iccData.dataType = data.toString('utf-8', 0, 2);
        
        // 再读取后面的四个字节表示正文长度
        iccData.dataLength = data.readUInt32BE(2);
        
        // 验证下长度是否正确
        if ((data.length - 6) != iccData.dataLength) {
            err = '接收的数据不完整';
        } else { 
            // 根据类型的不同分开处理
            switch (iccData.dataType) {
                case 'TX':
                    // 解析文本数据 
                    var xml = data.toString('utf-8', 6);
                    self.parseTXData(xml).then(function (result) {
                        iccData.txDataValue = result.DMITC;
                        self.recvCallback(iccData, err);
                    });
                    break;
                case 'BS':
                    break;
                case 'ER':
                    break;
                default:
                    err = '接收到未知类型数据';
            }
        }

        
    });
    
    this._session.on('error', function (err) {
        console.log('socket error: ' + err);
    });
    
    this._session.on('close', function () {
        console.log('connection closed');
        self._bConnect = false;
    });
};


serverConnector.prototype.sendDmitc = function (dmitc, callback) {
    var self = this;
    try {
        // 先设置成功回调
        self.recvCallback = callback || idleFunc;
        
        var funcSend = function (data) {
            var send_dmitc = data.toXml();
            
            var sendBuffer = new Buffer(send_dmitc.length + 6);
            sendBuffer.write('TX', 0, 2, 'utf-8');
            sendBuffer.writeInt32BE(send_dmitc.length, 2);
            sendBuffer.write(send_dmitc, 6, send_dmitc.length, 'utf-8');
            console.log(sendBuffer);
            
            // send
            self._session.write(sendBuffer);
        };
        
        if (!this._bConnect) {
            this._session.connect(this.port, this.host, function () {
                self._bConnect = true;
                console.log('Connect successful! host: ' + self.host + ' port: ' + self.port);
                
                funcSend(dmitc);
            });
        } else {
            funcSend(dmitc);
        }
    } catch (e) {
        console.error(e);
    }
};


serverConnector.prototype.parseTXData = function (xmlData) {
    var deferred = Q.defer();
    parseString(xmlData, {explicitArray: false}, function (err, result) {
        deferred.resolve(result);
    });

    return deferred.promise;
};

然后下面是请求:

/**
 * 客户端登录命令
 * */
var DMITC_Login = function (dataSource, userId, passWord) {
    this._dmitc = new DMITC('Login', 'post');
    
    this._dmitc.addParameter('Datasource', 'string', dataSource);
    this._dmitc.addParameter('UserID', 'string', userId);
    this._dmitc.addParameter('Password', 'string', passWord);
};

DMITC_Login.prototype.exec = function (serverConn, callback) {
    serverConn.sendDmitc(this._dmitc, function (data) {
        // 这个时候已经是接收完数据了
        var returnStatus = GetReturnStatus(data.txDataValue);
        if (callback) { 
            callback(returnStatus);
        }
    });
};
6 回复

值V:请求来请求去的,烦不烦啊,把偶当皮球踢吗??? 异步:怪我咯!!!

我只是做了个假设, 其实是有些处理是要放在Server端进行运算, 然后将结果返回的

我现在的问题就是, 怎么把Server端运算的结果,正确返回给前端页面的那个请求

web和webserver用socket.io通信即可,另外,node里一般err放在回调的第一个参数 自豪地采用 CNodeJS ionic

@luoyjx 谢谢, 我会尝试下

建议对数据进行封包处理,这样你服务端通过tcp返回的数据你就可以知道数据包的归宿,就可以执行对应的调用

回到顶部