节点socket.write返回的写入字节数多于原始缓冲区中的字节数

时间:2016-08-06 02:33:02

标签: node.js sockets tcp-ip

我正在使用节点函数来编译由头和有效负载组成的缓冲区。标头中的第一个术语是发送到服务器的缓冲区的总大小,第二个元素是发送到服务器的命令,然后将有效负载添加到缓冲区。当我计算所需缓冲区的长度时,使用NPM中的bufferpack.js库我得到的大小与创建缓冲区后的大小相同,我得到了缓冲区的length属性。

我看到的问题是,一旦缓冲区超过127个字节,写入的字节数与实际缓冲区中的字节数不匹配,在测试中,我已经完成了2个字节的更长时间。这导致服务器出现问题,因为它不知道如何处理额外的字节。

这是我用来将数据转换为缓冲区然后将缓冲区发送到服务器的方法

_sendall(cmd, payload='', callback){
  console.log('payload:', payload.length)
  let fmt = '>HB'
  let size = struct.calcLength(fmt) + payload.length
  console.log('size:',size)
  let header = [size, cmd]
  let buf = struct.pack(fmt, header) + payload
  console.log('buf:', buf.length)
  console.log('[INFO] Buffer Sent:',buf)
  this.sock.write(buf, 'binary', (err)=>{
    console.log('[INFO] Bytes written now:', this.sock.bytesWritten-this._bytesWrittenPrevious)
    console.log('[INFO] Total Bytes Written:', this.sock.bytesWritten)
    this._bytesWrittenPrevious = this.sock.bytesWritten
    if (err) {
      console.log('[ERROR] _sendall:', err)
      return callback(false)
    }
    return callback(true)
  })
}

以下是系统正常工作且发送的字节与缓冲区大小匹配时控制台输出的示例。服务器响应,一切都在世界上。

[INFO] Sending the input setup 
payload: 20 
size: 23 
buf: 23 
[INFO] Buffer Sent: Iinput_int_register_0 
[INFO] Bytes written now: 23 
[INFO] Total Bytes Written: 143

这是我在系统无法正常工作时看到的情况,服务器永远不会响应并且代码挂起,因为有回调从不触发。

[INFO] Sending the input setup
payload: 143
size: 146
buf: 146
[INFO] Buffer Sent: �Iinput_double_register_0,input_double_register_1,input_double_register_2,input_double_register_3,input_double_register_4,input_double_register_5
[INFO] Bytes written now: 148
[INFO] Total Bytes Written: 291

任何想法发生了什么?我无法找到任何关于这个问题的内容,所以非常感谢任何帮助。

更新:

我将@mscdex推荐的更改改为sock.write中的编码,现在我写的是我发送的相同字节数,但我仍然遇到问题。我已经缩小到使用bufferpack.js库编码为无符号短(H)的size元素。任何时候大小超过127我相信它编码错误,如果我尝试解压缩缓冲区我得到一个NaN返回值的大小。仍在努力解决这个问题。

2 个答案:

答案 0 :(得分:1)

当您发送二进制数据时,您不希望将'utf8'指定为编码。你真的应该使用Buffer对象而不是字符串来表示二进制数据。但是,要编写二进制字符串,可以使用'binary'编码。这将使字符串不被解释为UTF-8。

答案 1 :(得分:0)

我终于能够通过放弃bufferpack.js库来打包缓冲区来使程序工作。看来,只要缓冲区的大小超过127个字节,它就不会对正在正确发送的缓冲区的大小进行编码。 H变量中的fmt应该将字节格式化为unsigned short,似乎正在寻找签名的short,但这只是猜想,直到我有时间深入挖掘它因为我使用h得到了相同的结果,这是一个签名的短片。

为了解决这个问题,我转而使用本机缓冲区写入方法,这解决了这个问题。我将查看bufferpack.js并查看是否可以找到问题并将PR发布到repo,如果我能够纠正它。

以下是按预期工作的新代码:

_sendall(cmd, payload='', callback){
  let fmt = '>HB'
  let size = struct.calcLength(fmt) + payload.length
  let header = [size, cmd]
  let buf = new Buffer(size)
  buf.writeUInt16BE(size, 0)
  buf.writeInt8(cmd, 2)
  buf.write(payload.toString(), 3)
  this.sock.write(buf, 'binary', (err)=>{
    console.log('[INFO] Bytes written now:', this.sock.bytesWritten-this._bytesWrittenPrevious)
    console.log('[INFO] Total Bytes Written:', this.sock.bytesWritten)
    this._bytesWrittenPrevious = this.sock.bytesWritten
    if (err) {
      console.log('[ERROR] _sendall:', err)
      return callback(false)
    }
    return callback(true)
  })
}