我正在开发一个客户端应用程序,它通过TLS连接向服务器发送事务。应用程序发送给定数量的字节,并接收1182字节作为响应。在我开始增加每秒的事务数量之前,它一直工作正常。在那之后,一些响应数据包开始被破坏,并且不能被客户端完全接收。2当我试图打开数据包内容时,它引发了一个异常并终止了TLS会话。
javax.net.ssl.SSLException: Unrecognized record version (D)TLS-0.0 , plaintext connection?
at java.base/sun.security.ssl.SSLEngineInputRecord.bytesInCompletePacket(SSLEngineInputRecord.java:98)
at java.base/sun.security.ssl.SSLEngineInputRecord.bytesInCompletePacket(SSLEngineInputRecord.java:64)
at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:544)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:441)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:420)
at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:634)
at MyClass.handleEncryptedTransaction(MyClass.java:297)
我尝试使用缓冲区来累积可能损坏的包,但是在解封装之前我无法看到包的内容,只能根据包的大小来估计包是否完整。
this.peerNetData.clear();
int bytesRead = socketChannel.read(this.peerNetData);
if (bytesRead == DEFAULT_TLS_HANDSHAKE_SIZE) {
handleEncryptedTransaction(socketChannel, engine);
} else if (bytesRead > 0) {
// TLS packet buffering
byte[] justRead = new byte[this.peerNetData.position()];
this.peerNetData.flip();
this.peerNetData.get(justRead);
this.incompleteTransactionsBuffer.put(justRead);
// DEFAULT_TLS_TRANSACTION_SIZE == 1182
if (this.incompleteTransactionsBuffer.position() >= DEFAULT_TLS_TRANSACTION_SIZE) {
this.incompleteTransactionsBuffer.flip(); // flipping to read mode
while (this.incompleteTransactionsBuffer.remaining() >= DEFAULT_TLS_TRANSACTION_SIZE) {
byte[] fullTransaction = new byte[DEFAULT_TLS_TRANSACTION_SIZE];
this.incompleteTransactionsBuffer.get(fullTransaction, 0, fullTransaction.length);
this.peerNetData.clear();
this.peerNetData.put(fullTransaction);
// This method uses this.peerNetData to unwrap data and
handleEncryptedTransaction(socketChannel, engine);
}
this.incompleteTransactionsBuffer.compact(); // wipe out bytes that had been read and free space of the buffer
}
}
**是否有任何方法可以检查TLS上的TCP数据包是否完整?**我尝试读取前1182个字节,但似乎不起作用。有趣的是,当我在响应中获得多个数据包时,此代码起作用,例如(N * 1182),其中N从2到7不等。也许我应该等待另一个套接字读取并获得另一条信息?
我想这个问题是因为流量过大导致的数据包重传而引起的。在Java中,是否有其他方法可以处理低级套接字连接中的TLS数据包重传?
1条答案
按热度按时间eit6fx6z1#
在得到评论和更好地理解TLS协议之后,我可以通过实现缓冲区并获得TLS记录的确切大小来等待其他TCP读取来找到问题的解决方案。
一个TLS记录“可能被分割成多个TCP片段,或者TCP片段也可能包含多个完整的、一半的或其他的TLS记录。这些TCP片段甚至可能被分割成多个IP数据包,尽管TCP努力避免这种情况。",来自Determine packet size of TLS packet Java/Android。然而,该帖子提到了前2个字节,这是不正确的。根据https://hpbn.co/transport-layer-security-tls/#tls-record-diagram:
最大TLS记录大小为16 KB
每条记录包含一个5字节的报头、一个MAC(SSLv3、TLS 1.0、TLS 1.1最多20字节,TLS 1.2最多32字节)和填充(如果使用块密码)。
要解密和验证记录,必须提供整个记录。
TLS记录大小取决于第3和第4字节:
代码最后是这样的: