我正在设置一个简单的测试,用于在套接字上发送二进制数据。
在发送端,我只是编码传递给调用的参数的数量,然后对于每个参数,我编码该参数的长度。这为我提供了一种快速简便的方法来测试发送不同的二进制数据:
var client = new net.Socket()
client.connect(9999, host, function() {
console.log("Connected")
// convert argument list into length delimited parameters
var i,args = process.argv.length-3
var buf = new Buffer(4)
buf.writeInt32LE(args,0)
client.write(buf)
console.log("sending "+args+" args")
for (i=3;i<args+3;i++) {
console.log("["+(i-3)+"] "+process.argv[i].length)
buf.writeInt32LE(process.argv[i].length)
client.write(buf)
}
client.end()
})
在接收方面,我增加了参数的数量,然后对于每个参数,我提取该参数的长度,并打印整个事物。我使用一个小状态机来跟踪我在阅读中的位置。
var server = net.createServer(function(x) {
console.log("connected")
var state=0,args,argn
x.on("readable",function() {
switch (state) {
case 0:
var n = x.read(4)
console.log("[0]"); console.dir(n)
if (n === null) return
args=n.readInt32LE(0)
console.log(args+" arguments")
state = 1 ; argn = 0
break
case 1:
var n = x.read(4)
console.log("[1]"); console.dir(n)
if (n === null) return
console.log("argument "+argn+" has "+n.readInt32LE(0)+" bytes")
if (++argn > args) {
console.log("end of arguments")
state = 0
}
break
default:
console.log("state="+state+", now what?")
}
})
x.on("close",function() { console.log("closed") })
x.on("end",function() { console.log("ended") })
server.listen({port:9999})
我看到的问题是我似乎永远不会收到最后两个参数长度(32位整数)。我已经尝试在发送端发送一个或两个额外的整数,只是为了看它是否有所作为,但事实并非如此。我根本没有看到曾经多次调用的可读回调。
例如,如果在客户端我调用:
node tcptest.js tx "Hello world" 12345 AAA 9
客户端的输出是:
sending
Connected
sending 4 args
[0] 10
[1] 5
[2] 3
[3] 1
Connection closed
但在服务器端,我看到的只有:
receiving
connected
[0]
Buffer [ 4, 0, 0, 0 ]
4 arguments
[1]
Buffer [ 10, 0, 0, 0 ]
argument 0 has 10 bytes
[1]
Buffer [ 5, 0, 0, 0 ]
argument 1 has 5 bytes
socket ended
socket closed
我尝试不重复使用buf
对象并且它已经工作了一段时间,但后来开始间歇性地失败了。
...
for (i=3;i<args+3;i++) {
buf = new Buffer(4)
console.log("["+(i-3)+"] "+process.argv[i].length)
...
当它再次开始工作一段时间后,我想也许有一些没有记录的东西,不允许缓冲区被重复用于传递写入,但现在我不知道。如果我根本不使用缓冲区,例如如果我将stdin传递给套接字,那么它工作正常,但是如果我尝试构造像这样的二进制数据并不总是得到接收。
我可能做错了什么?
更新:
如果我在服务器端调用read()
而不是指定字节数,那么我会看到收到的所有数据!我怀疑发生的事情是,如果我读取的字节数少于可用的字节数,我就不会得到额外的回调。
答案 0 :(得分:0)
“可读”事件仅针对收到的每个附加数据块触发一次。如果没有读取所有可用数据,上面的代码假定它会在返回时再次触发,但事实并非如此。
以下代码通过将状态机包装在一个循环中来解决问题,该循环继续提取数据,直到它无法获取下一个预期的块:
x.on("readable",function() {
while (true) {
switch (state) {
case 0:
var n = x.read(4)
console.log("[0]"); console.dir(n)
if (n === null) return
args=n.readInt32LE(0)
console.log(args+" arguments")
state = 1 ; argn = 0
break
case 1:
var n = x.read(4)
console.log("[1]"); console.dir(n)
if (n === null) return
console.log("argument "+argn+" has "+n.readInt32LE(0)+" bytes")
if (++argn > args) {
console.log("end of arguments")
state = 0
}
break
default:
console.log("state="+state+", now what?")
return
}
}