javascript - 为何Java发送数据会被拆包而用NodeJs就不会?

查看:162
本文介绍了javascript - 为何Java发送数据会被拆包而用NodeJs就不会?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

const net = require('net');

const str = '3c3f8f6e7c8d9c1a2s3d4f6f';//此处省略大部分数据

console.log(str.length);

const buf = Buffer.allocUnsafe(4);
buf.writeInt32BE(str.length / 2);

let totalBuf = buf;
for (let i = 0; i <str.length; i += 2) {
    let hex = str.substr(i, 2);
    console.log('str: ' + hex);
    hex = parseInt(hex, 16);
    console.log('hex: ' + hex);
    const temp = Buffer.allocUnsafe(1);
    temp.writeInt8(hex, 0, 1, true);
    totalBuf = Buffer.concat([totalBuf, temp]); 
    console.log(totalBuf);
}
console.log(totalBuf);

const client = net.connect(3000, '172.11.111.25', () => {
  // 'connect' listener
  console.log('connected to server!');
  client.write(totalBuf);
});
client.on('data', (data) => {
  console.log(data.toString());
  client.end();
});
client.on('end', () => {
  console.log('disconnected from server');
});

js代码如上所示,抓包得到:

可以看出前三条报文分别为
TCP的三次握手:SYN,对方发来的SYN + ACK,ACK
第四条报文为数据(PSU),有674个字节
第五条报文是对方发来的对第四条报文的确认
第六条是对方(Java写的系统)发来的数据,只有一个字节
第七条我方确认,第八条对方数据,三个字节,
第九条我方确认,第十条我方FIN
第十一条对方数据,830字节
第六,七,十一条组成了报文的数据组合起来才是完整的,说明发生了拆包,拆包原因不明。

以下是我用Java发送数据,同样发生了拆包:

代码如下:

   public byte[] requestSend(byte[] data, boolean synRespFlag) throws Exception {
     try {
       DataOutputStream dataout = new DataOutputStream(
         this.commSock.getOutputStream());
       if (data != null) {
         dataout.writeInt(data.length);
         dataout.write(data);
         String output = new String(data);
         MyLogger.getInstance().info("待发送的报文数据为:\n" + output);
       }
       dataout.flush();
      //  dataout.close();
       if (synRespFlag) {
         DataInputStream datain = new DataInputStream(
           this.commSock.getInputStream());
         int readTimeout = Integer.parseInt(GlobalConfig.getInstance()
           .getResponseTimeout());
         this.commSock.setSoTimeout(readTimeout);
         int dataLength = datain.readInt();
         MyLogger.getInstance().info("报文长度为:" + dataLength);
         byte[] recvBuffer = new byte[dataLength];
         datain.read(recvBuffer, 0, dataLength);
         String input = new String(recvBuffer);
         MyLogger.getInstance().info("接收报文数据:\n" + input);
         datain.close();
         dataout.close();
         return recvBuffer;
       }
       return null;
     }
     catch (Exception e) {
       MyLogger.getInstance().error(
         "发送请求数据出错:" + ExceptionInfo.getInfo(e));
       throw e;
     }
   }

抓包:

数据被分散到第四和第六条报文,分别为1字节和673字节。

解决方案

用TCP发送和接收数据时,一定要做好两个假设:
一段数据可能在任意位置被拆开;
前后两段数据可能在会被粘在一起。
这两种情况可以认为是随机发生的。

拆和粘不一定由语言、操作系统引起,也可能是由路由器引起的。

所以并不能保证NodeJS一定不会拆,也不能保证Java一定会拆,只是可能NodeJS和Java在操作系统层TCP调用时,实现机制不同,但开发者应该无视这种不同,严格按照前面两条假设来处理数据。

UPDATE

仔细看了问题中的Java代码,发现用了DataOutputStream,这个很坑的,看下源码就知道了,它对writeInt是分4次write的。

有两种方式可以改善发送效率:

  1. 再用BufferedOutputStream包一层;

  2. 不要用DataOutputStream,而是自己拼装byte[],一次性用SocketOutputStream直接发掉,在这个例子中可以用byte[4 + data.length]

这篇关于javascript - 为何Java发送数据会被拆包而用NodeJs就不会?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆