为何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]

以上是 为何Java发送数据会被拆包而用NodeJs就不会? 的全部内容, 来源链接: utcz.com/p/178666.html

回到顶部