Node.js套接字的等效于php的fgetc()是什么?

3
什么是Node.js中类似于PHP中fgetc()函数的等效函数?我如何将其应用于套接字?
我正在开发这个PHP脚本的Node.js端口: http://code.google.com/p/bf2php/source/browse/trunk/rcon/BF2RConBase.class.php 基本上,它使用套接字连接到基于Battlefield 2的游戏服务器。我正在查看的函数是:
protected function read($bare = false) {
    $delim = $bare ? "\n" : "\x04";
    for($buffer = ''; ($char = fgetc($this->socket)) != $delim; $buffer .= $char);
    return trim($buffer);
}

据我了解,它应该直接从套接字中逐个字符抓取第一行,直到'\n'为止。 我假设输出用于获取加密盐。 该函数在套接字连接事件中被调用,作为生成所需的加密密码的代码的一部分。 有人能展示一个类似于此函数的Node.js等效函数吗?


在进行移植时,您可能会发现这个链接很有帮助:https://github.com/cranic/node-phpjs - hakre
谢谢您的回复。我不确定我甚至理解它是做什么的。那里没有太多的文档。但再次感谢! - lee8oi
phpjs是将所有PHP函数转换为JavaScript的库。该库已经被移植到了Node.js上。其中fgetc端口可能包含您正在寻找的代码。虽然有点复杂,但应该会有所帮助。您也可以直接将PHP代码转换为JS,因为您已经拥有了所有的PHP函数。 - hakre
1个回答

1

文档提供了一个非常好的示例,展示如何通过网络连接到服务器。

var net = require('net');
var client = net.connect({port: 8124},
    function() { //'connect' listener
  console.log('client connected');
  client.write('world!\r\n');
});
client.on('data', function(data) {
  console.log(data.toString());
  client.end();
});
client.on('end', function() {
  console.log('client disconnected');
});

只需将data事件处理程序更改为缓冲传入的数据,直到您收到所需信息。

为此,您需要知道如何使用{{link1:Buffer}}。


这是一个具体的例子,演示如何从流中缓冲数据并解析出由特定字符分隔的消息。我注意到在链接的PHP代码中,您尝试实现的协议使用EOT(0x04)字符作为消息分隔符。
var net = require('net');


var max = 1024 * 1024 // 1 MB, the maximum amount of data that we will buffer (prevent a bad server from crashing us by filling up RAM)
    , allocate = 4096; // how much memory to allocate at once, 4 kB (there's no point in wasting 1 MB of RAM to buffer a few bytes)
    , buffer=new Buffer(allocate) // create a new buffer that allocates 4 kB to start
    , nread=0 // how many bytes we've buffered so far
    , nproc=0 // how many bytes in the buffer we've processed (to avoid looping over the entire buffer every time data is received)
    , client = net.connect({host:'example.com', port: 8124}); // connect to the server

client.on('data', function(chunk) {
    if (nread + chunk.length > buffer.length) { // if the buffer is too small to hold the data
        var need = Math.min(chunk.length, allocate); // allocate at least 4kB
        if (nread + need > max) throw new Error('Buffer overflow'); // uh-oh, we're all full - TODO you'll want to handle this more gracefully

        var newbuf = new Buffer(buffer.length + need); // because Buffers can't be resized, we must allocate a new one
        buffer.copy(newbuf); // and copy the old one's data to the new one
        buffer = newbuf; // the old, small buffer will be garbage collected
    }

    chunk.copy(buffer, nread); // copy the received chunk of data into the buffer
    nread += chunk.length; // add this chunk's length to the total number of bytes buffered

    pump(); // look at the buffer to see if we've received enough data to act
});

client.on('end', function() {
    // handle disconnect
});


client.on('error', function(err) {
    // handle errors
});


function find(byte) { // look for a specific byte in the buffer
    for (var i = nproc; i < nread; i++) { // look through the buffer, starting from where we left off last time
        if (buffer.readUInt8(i, true) == byte) { // we've found one
            return i;
        }
    }
}
function slice(bytes) { // discard bytes from the beginning of a buffer
    buffer = buffer.slice(bytes); // slice off the bytes
    nread -= bytes; // note that we've removed bytes
    nproc = 0; // and reset the processed bytes counter
}

function pump() {
    var pos; // position of a EOT character

    while ((pos = find(0x04)) >= 0) { // keep going while there's a EOT (0x04) somewhere in the buffer
        if (pos == 0) { // if there's more than one EOT in a row, the buffer will now start with a EOT
            slice(1); // discard it
            continue; // so that the next iteration will start with data
        }
        process(buffer.slice(0,pos)); // hand off the message
        slice(pos+1); // and slice the processed data off the buffer
    }
}

function process(msg) { // here's where we do something with a message
    if (msg.length > 0) { // ignore empty messages
        // here's where you have to decide what to do with the data you've received
        // experiment with the protocol
    }
}

完全未经测试,因此可能存在错误。这里需要注意的主要事项是,随着数据的到达,您需要在内存中缓冲它。一旦在缓冲区中找到分隔符字符,就可以处理消息。


缓冲区!好的。这是一个很好的开始。我实际上正在查看流来尝试弄清楚它们。缓冲区在某个地方引起了我的注意,但没有留下深刻印象。我会更仔细地研究它们。谢谢!还有感谢您的快速回复 :) - lee8oi
@user1287536:是的,Stream 是网络连接、文件读取器、加密和(解)压缩等东西的超类。它们的 data 事件通常会发出 Buffer。还可以查看此流缓冲示例。在那个答案中,我正在缓冲 gzip 的输出,但缓冲网络流非常相似。 - josh3736
有道理。我在你的缓冲代码里看到了一些东西。这确实让我想到了如何将其应用到我的代码中。谢谢! - lee8oi
实际上,我可能回到了原点。我正在检查“data”事件返回的数据,但我看不到任何类似于盐或加密的东西,只有普通文本。从我所看到的缓冲区只是一个存储所有数据块的地方。我需要以某种方式从流本身中获取一些信息。在PHP中,fgetc()函数读取流而不是缓冲区。 - lee8oi
好的,我已经尝试了一些东西,并发现答案比预期简单得多。我真的觉得自己过度思考了,感觉像个白痴。@josh3736,你关于缓冲区的说法是正确的,只有数据事件实际上返回了一个缓冲区。我只需要将它转换为toString()即可使用。 - lee8oi
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接