我正在努力及时检测Java TLS套接字上的连接重置。
我正在处理丢失消息的syslog-over-TLS客户端。 syslog客户端在到达消息时就发送消息,并为此目的保持打开一个TLS套接字,除非出现错误,否则它将丢弃该套接字并打开新的连接。
为调查此问题,我一次又一次发送相同类型和大小的消息。
将发生以下情况:
用于发送消息的代码很简单:
OutputStream out = socket.getOutputStream();
out.write(syslogFrame);
out.write(msgBytes);
out.flush();
为什么在上面的代码中,第二次写操作最晚才在第二条消息上没有收到异常?我该如何确定自己呢?
该消息远大于MTU,并且I / O图清楚地表明,第二条消息甚至都不是通过电线发送的:
完整跟踪:连接在数据包2处建立。直到#27的数据包都是第一条消息的传输。 #28,#29,#30是通过连接重置回答的第二条消息的开头。此时,Java代码中没有引发异常。套接字写操作返回,没有错误,但消息丢失。现在,对第3条消息的写入操作会收到“连接重置”异常,该异常触发客户端代码在数据包#33 ff中重新建立连接,然后第3条消息通过网络传输。
我运行客户机的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。
答案 0 :(得分:0)
问题实际上是在TCP上实现的所有单纯形协议固有的。 Java的写操作往往会在实际将任何字节压入TCP堆栈之前返回,这样的事实会加剧这种情况。甚至不在flush()
上。因此,发信号在设计上是不可靠的。
确定套接字连接状况的唯一可靠方法是通过读取套接字连接状况。但是,使用单纯形协议,无需阅读任何内容。这就是为什么rsyslog实现RELP protocol的原因,它添加了一个反向通道,通过该反向通道发送应用程序级ACK / NAK消息。