node 第七章TCP通讯的拆包与封包

TCP粘包问题

1: 在通讯的过程中,我们可能有发送多个数据包,数据包A,数据包B,数据包C,此时我们最好的期望是每次收到数据包A,数据包B,数据包C。但是TCP底层为了传送性能,可能会一次把ABC所有数据一起传过来,这个时候收到的是A+B+C,这个时候上层傻眼了,无法区分A,B,C这个叫做---粘包;

包体协议

1:要解决ABC数据包无法正确的拆分出A,B,C三个数据,我们需要在ABC之间插入长度/分解标志,这样根据长度和分解标志来解析出ABC的数据包;

2: 打入长度信息两种方式:       (1)“数据长度” + 包体  (2)(包体 + 特定的结尾符号)

3: 本例采用 数据长度 +包体的方式。 数据长度2个字节,超过2个字节大小的数据,上层可以分多次发送;

4: 这里的包,是上层的应用协议的包,与TCP的包是两回事;

TCP 封包拆包实现
 

// 根据封包协议我们读取包体的长度;
read_pkg_size: function(pkg_data, offset) {
   if (offset > pkg_data.length - 2) { // 没有办法获取长度信息的;
      return -1; 
   }

   var len = pkg_data.readUInt16LE(offset);
   return len;
},

// 把一个要发送的数据,封包 2个字节的长度 + 数据
// data string 二进制的buffer
package_data: function(data) {
   var buf = Buffer.allocUnsafe(2 + data.length);
   buf.writeInt16LE(2 + data.length, 0);
   buf.fill(data, 2);

   return buf;
},
client_sock.on("data", function(data) {
   console.log(data);
   if (last_pkg != null) { // 上一次剩余没有处理完的半包;
      var buf = Buffer.concat([last_pkg, data], last_pkg.length + data.length);
      last_pkg = buf;
   }
   else {
      last_pkg = data;   
   }

   var offset = 0;
   var pkg_len = netpkg.read_pkg_size(last_pkg, offset);
   if (pkg_len < 0) {
      return;
   }

   while(offset + pkg_len <= last_pkg.length) { // 判断是否有完整的包;
      // 根据长度信息来读取我们的数据,架设我们穿过来的是文本数据
      var cmd_buf = Buffer.allocUnsafe(pkg_len - 2); // 2个长度信息
      last_pkg.copy(cmd_buf, 0, offset + 2, offset + pkg_len);

      console.log("recv Cmd: ", cmd_buf); // cmdbuf ,用户发过来的命令的数据;
      console.log(cmd_buf.toString("utf8"));

      offset += pkg_len;
      if (offset >= last_pkg.length) { // 正好我们的包处理完了;
         break;
      }

      pkg_len = netpkg.read_pkg_size(last_pkg, offset);
      if (pkg_len < 0) {
         break;
      }
   }

   // 能处理的数据包已经处理完成了,保存 0.几个包的数据
   if (offset >= last_pkg.length) {
      last_pkg = null;
   }
   else { // offset, length这段数据拷贝到新的Buffer里面
      var buf = Buffer.allocUnsafe(last_pkg.length - offset);
      last_pkg.copy(buf, 0, offset, last_pkg.length);
      last_pkg = buf;
   }
   // end 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值