Java TLS套接字写入无法检测到连接重置

时间:2018-10-08 15:27:10

标签: java sockets tls1.2

我正在努力及时检测Java TLS套接字上的连接重置。

我正在处理丢失消息的syslog-over-TLS客户端。 syslog客户端在到达消息时就发送消息,并为此目的保持打开一个TLS套接字,除非出现错误,否则它将丢弃该套接字并打开新的连接。

为调查此问题,我一次又一次发送相同类型和大小的消息。

将发生以下情况:

  1. 启动客户端
  2. 第一条消息到达-打开新套接字,并将消息成功传输到远程syslog(下面的代码)
  3. 闲置15分钟
  4. 第二条消息到达-现有套接字用于发送消息; tcp连接重置已收到,但未引发任何异常;消息丢失了
  5. 第三条消息不久之后到达-立即写入套接字失败,但出现以下异常:连接重置;客户端打开新套接字并成功发送消息

用于发送消息的代码很简单:

OutputStream out = socket.getOutputStream();
out.write(syslogFrame);
out.write(msgBytes);
out.flush();

为什么在上面的代码中,第二次写操作最晚才在第二条消息上没有收到异常?我该如何确定自己呢?

该消息远大于MTU,并且I / O图清楚地表明,第二条消息甚至都不是通过电线发送的:

enter image description here

完整跟踪:连接在数据包2处建立。直到#27的数据包都是第一条消息的传输。 #28,#29,#30是通过连接重置回答的第二条消息的开头。此时,Java代码中没有引发异常。套接字写操作返回,没有错误,但消息丢失。现在,对第3条消息的写入操作会收到“连接重置”异常,该异常触发客户端代码在数据包#33 ff中重新建立连接,然后第3条消息通过网络传输。

enter image description here

我运行客户机的OS是Linux Mint 18.3(内核4.10.0-38通用),带有Oracle JDK 1.8.0_172和10.0.2; CentOS Linux 7.5.1804(内核3.10.0-693.21.1.el7.x86_64)和Oracle JDK 1.8.0_172。

1 个答案:

答案 0 :(得分:0)

问题实际上是在TCP上实现的所有单纯形协议固有的。 Java的写操作往往会在实际将任何字节压入TCP堆栈之前返回,这样的事实会加剧这种情况。甚至不在flush()上。因此,发信号在设计上是不可靠的。

确定套接字连接状况的唯一可靠方法是通过读取套接字连接状况。但是,使用单纯形协议,无需阅读任何内容。这就是为什么rsyslog实现RELP protocol的原因,它添加了一个反向通道,通过该反向通道发送应用程序级ACK / NAK消息。