Javascript Node.js TCP服务器传入缓冲区

Javascript Node.js TCP服务器传入缓冲区,javascript,tcp,node.js,Javascript,Tcp,Node.js,我有两个相互通信的节点进程。我会叫他们[节点服务器]和[节点发送者][Node Sender]持续处理信息,并通过TCP连接将消息写入[Node Server][节点服务器]然后写回一条状态消息 [Node Sender]的示例: var message = "Test Message"; [Node Sender].connection.write(message); [节点服务器]的示例: [Node Server].socket.on("data", function(p_data) {

我有两个相互通信的节点进程。我会叫他们[节点服务器][节点发送者][Node Sender]持续处理信息,并通过TCP连接将消息写入[Node Server][节点服务器]然后写回一条状态消息

[Node Sender]的示例:

var message = "Test Message";
[Node Sender].connection.write(message);
[节点服务器]的示例:

[Node Server].socket.on("data", function(p_data) {
    this.write("OK");

    // Do some work with p_data
}
这项工作没有问题,p_数据在5毫秒以上发送时始终包含“测试消息”。但是,如果我将[Node Sender]加速到每毫秒写入一次,p_data偶尔会以类似“Test MessageTest MessageTes”的内容结束

我知道[Node Sender]中的缓冲区填充速度可能比write命令发送的速度快。有没有一种方法可以在仍然保持异步的情况下强制发送消息时采用一对一的比率


我当然可以在我的邮件中添加一个终止符,并在[Node Server]中填充一个缓冲区,但我想确保没有明显的遗漏。

不,您没有遗漏任何内容,是的,您确实需要在邮件中添加某种形式的终止

这里有两个基本问题:

  • TCP协议是面向流的,而不是面向消息的;它不知道什么可能构成“信息”

  • node.js net library触发的数据事件表示某些数据已到达,但不知道消息可能包含哪些内容,因此无法表示它已收到任何特定数据

  • 因此,通过发送消息的速度比节点处理消息的速度快,套接字recv缓冲区将填充多条“消息”

    此问题的典型解决方案是添加线路终端,如中所示 在第32-34行:

    self.client.on('data', function (data) {
        self.process_data(data);
    });
    
    第110-134行:

    Connection.prototype.process_data = function (data) {
      if (this.disconnected) {
        logger.logwarn("data after disconnect from " + this.remote_ip);
        return;
      }
    
      this.current_data += data;
      this._process_data();
    };
    
    Connection.prototype._process_data = function() {
      var results;
      while (results = line_regexp.exec(this.current_data)) {
        var this_line = results[1];
        if (this.state === 'pause') {
            this.early_talker = 1;
            var self = this;
            // If you talk early, we're going to give you a delay
            setTimeout(function() { self._process_data() }, this.early_talker_delay);
            break;
        }
        this.current_data = this.current_data.slice(this_line.length);
        this.process_line(this_line);
      }
    };
    

    您需要累积传入缓冲区数据以获得完整的消息。请参考下面的例子。此服务器需要具有4字节标头和消息正文的数据。标头是无符号整数,表示正文的总长度,正文是带分隔符“|”的字符串数据。请注意,可能一次未收到此“标题和消息”。因此,我们需要累积传入数据,直到获得完整长度的数据。同时也可能一次收到多个“标题和消息”。关键是我们需要积累数据

    var SERVER_PORT = 8124;
    var TCP_DELIMITER = '|';
    var packetHeaderLen = 4; // 32 bit integer --> 4
    
    var server = net.createServer( function(c) {
        var accumulatingBuffer = new Buffer(0); 
        var totalPacketLen   = -1; 
        var accumulatingLen  =  0;
        var recvedThisTimeLen=  0;
        var remoteAddress = c.remoteAddress;
        var address= c.address();
        var remotePort= c.remotePort;
        var remoteIpPort = remoteAddress +":"+ remotePort;
    
        console.log('-------------------------------'+remoteAddress);
        console.log('remoteIpPort='+ remoteIpPort); 
    
        c.on('data', function(data) {
            console.log('received data length :' + data.length ); 
            console.log('data='+ data); 
    
            recvedThisTimeLen = data.length;
            console.log('recvedThisTimeLen='+ recvedThisTimeLen);
    
            //accumulate incoming data
            var tmpBuffer = new Buffer( accumulatingLen + recvedThisTimeLen );
            accumulatingBuffer.copy(tmpBuffer);
            data.copy ( tmpBuffer, accumulatingLen  ); // offset for accumulating
            accumulatingBuffer = tmpBuffer; 
            tmpBuffer = null;
            accumulatingLen += recvedThisTimeLen ;
            console.log('accumulatingBuffer = ' + accumulatingBuffer  ); 
            console.log('accumulatingLen    =' + accumulatingLen );
    
            if( recvedThisTimeLen < packetHeaderLen ) {
                console.log('need to get more data(less than header-length received) -> wait..');
                return;
            } else if( recvedThisTimeLen == packetHeaderLen ) {
                console.log('need to get more data(only header-info is available) -> wait..');
                return;
            } else {
                console.log('before-totalPacketLen=' + totalPacketLen ); 
                //a packet info is available..
                if( totalPacketLen < 0 ) {
                    totalPacketLen = accumulatingBuffer.readUInt32BE(0) ; 
                    console.log('totalPacketLen=' + totalPacketLen );
                }
            }    
    
            //while=> 
            //in case of the accumulatingBuffer has multiple 'header and message'.
            while( accumulatingLen >= totalPacketLen + packetHeaderLen ) {
                console.log( 'accumulatingBuffer= ' + accumulatingBuffer );
    
                var aPacketBufExceptHeader = new Buffer( totalPacketLen  ); // a whole packet is available...
                console.log( 'aPacketBufExceptHeader len= ' + aPacketBufExceptHeader.length );
                accumulatingBuffer.copy( aPacketBufExceptHeader, 0, packetHeaderLen, accumulatingBuffer.length); // 
    
                ////////////////////////////////////////////////////////////////////
                //process one packet data
                var stringData = aPacketBufExceptHeader.toString();
                var usage = stringData.substring(0,stringData.indexOf(TCP_DELIMITER));
                console.log("usage: " + usage);
                //call handler
                (serverFunctions [usage])(c, remoteIpPort, stringData.substring(1+stringData.indexOf(TCP_DELIMITER)));
                ////////////////////////////////////////////////////////////////////
    
                //rebuild buffer
                var newBufRebuild = new Buffer( accumulatingBuffer.length );
                newBufRebuild.fill();
                accumulatingBuffer.copy( newBufRebuild, 0, totalPacketLen + packetHeaderLen, accumulatingBuffer.length  );
    
                //init      
                accumulatingLen -= (totalPacketLen +4) ;
                accumulatingBuffer = newBufRebuild;
                newBufRebuild = null;
                totalPacketLen = -1;
                console.log( 'Init: accumulatingBuffer= ' + accumulatingBuffer );   
                console.log( '      accumulatingLen   = ' + accumulatingLen );  
    
                if( accumulatingLen <= packetHeaderLen ) {
                    return;
                } else {
                    totalPacketLen = accumulatingBuffer.readUInt32BE(0) ; 
                    console.log('totalPacketLen=' + totalPacketLen );
                }    
            }  
        }); 
    
        ...
    });
    
    var服务器_端口=8124;
    var TCP_分隔符='|';
    变量packetHeaderLen=4;//32位整数-->4
    var server=net.createServer(函数(c){
    var累加缓冲区=新缓冲区(0);
    var totalPacketLen=-1;
    var累加Len=0;
    var recvedThisTimeLen=0;
    var remoteAddress=c.remoteAddress;
    var address=c.address();
    var remotePort=c.remotePort;
    var remoteIpPort=remoteAddress+“:”+remotePort;
    console.log('------------------------------------'+远程地址);
    log('remoteIpPort='+remoteIpPort);
    c、 on('data',函数(data){
    console.log('接收到的数据长度:'+data.length);
    console.log('data='+数据);
    recvedThisTimeLen=data.length;
    log('recvedThisTimeLen='+recvedThisTimeLen);
    //累积传入数据
    var tmpBuffer=新缓冲区(累加Len+recvedThisTimeLen);
    累积缓冲区副本(tmpBuffer);
    data.copy(tmpBuffer,累加len);//累加的偏移量
    累加缓冲区=tmpBuffer;
    tmpBuffer=null;
    累加Len+=已接收此TimeLen;
    log('accumulatingBuffer='+accumulatingBuffer);
    console.log('accumulatingLen='+accumulatingLen);
    如果(记录此时间段<包装标题段){
    log('需要获取更多数据(小于接收到的标头长度)->等待..');
    返回;
    }else if(recvedThisTimeLen==packetHeaderLen){
    log('需要获取更多数据(只有标题信息可用)->等待..');
    返回;
    }否则{
    log('before-totalPacketLen='+totalPacketLen);
    //数据包信息可用。。
    if(总包装长度<0){
    totalPacketLen=累加缓冲区readUInt32BE(0);
    log('totalPacketLen='+totalPacketLen);
    }
    }    
    //while=>
    //在累加的情况下,缓冲区有多个“头和消息”。
    while(累计长度>=totalPacketLen+packetHeaderLen){
    log('accumulatingBuffer='+accumulatingBuffer);
    var aPacketBufExceptHeader=新缓冲区(totalPacketLen);//整个数据包可用。。。
    log('aPacketBufExceptHeader len='+aPacketBufExceptHeader.length);
    accumulatingBuffer.copy(aPacketBufExceptHeader,0,packetHeaderLen,accumulatingBuffer.length);//
    ////////////////////////////////////////////////////////////////////
    //处理一个数据包
    var stringData=aPacketBufExceptHeader.toString();
    var usage=stringData.substring(0,stringData.indexOf(TCP_分隔符));
    console.log(“用法:+用法”);
    //呼叫处理程序
    (serverFunctions[usage])(c,remoteiPort,stringData.substring(1+stringData.indexOf(TCP_分隔符));
    ////////////////////////////////////////////////////////////////////
    //重建缓冲区
    var newbuffrebuild=新缓冲区(累加Buffer.length);
    newBufRebuild.fill();
    累加buffer.copy(newbufferuild,0,totalPacketLen+packetHeaderLen,累加buffer.length);
    //初始化
    累计长度-=(总包装长度+4);
    累加缓冲区=新缓冲区重建;
    newBufRebuild=null;