我正在使用非常基本的Java套接字编程在不可靠的无线电网络(家庭酿造)上进行一些实验,以在端节点之间来回传递消息。
设置如下:
节点A ---中继节点---节点B
我经常遇到的一个问题是,某种程度上连接断开,节点A或B都不知道链路已经死亡,但仍继续传输数据。 TCP连接也没有超时。我在心跳消息中添加了一段时间后会导致超时,但我仍然想知道为什么TCP没有超时的根本原因是什么。
以下是我在设置套接字时启用的选项:
channel.socket().setKeepAlive(false);
channel.socket().setTrafficClass(0x08); // for max throughput
这种行为很奇怪,因为它与我有有线网络完全不同。在有线网络上,我可以通过拔出以太网线来模拟断开的连接,但是,一旦我重新插入电源线,连接就会重新建立,并且消息会再次通过。
在无线电网络上,连接永远不会重新建立,一旦它无声地消亡,消息就永远不会恢复。
我是否可以使用其他一些未知的java实现或套接字设置,为什么我首先看到这种行为?
是的,在任何人说什么之前,我知道TCP不是不可靠网络的优先选择,但在这种情况下我想确保没有数据包丢失。
答案 0 :(得分:2)
TCP协议设计得很安静。 RFC要求keepalive心跳不超过2小时。除非您可以控制两端的系统以更改默认的2小时心跳(有时需要内核重建),否则您必须在自己的应用中添加心跳。
如果你发送心跳,它仍然需要等到重新传输超时,这取决于RTT。在高延迟网络上,超时可能非常高,但应该在几分钟之内。
您可以在本地网络上收到通知,因为系统可以检测链路断开状态并删除该网络上的所有连接。
顺便说一下,你想把Keepalive设置为TRUE,而不是false。使用Keepalive,你至少可以获得缓慢的心跳。
答案 1 :(得分:2)
在OSI 7层模型中,前两层是物理和数据链路。在有线以太网上运行数据链路协议的物理硬件可以检测何时拉出电缆。您的无线硬件和相应的协议可能不是那么多。如果第1层/第2层没有发出断开信号,则TCP堆栈无法执行任何操作。
答案 2 :(得分:1)
定义'never'?
我希望最终发送失败会通知您。你可能只是期望比你更早得到通知。 TCP堆栈将重新传输它没有获得ACK的段,并且每次重传时重传之前的超时每次重传时加倍。根据堆栈的运行时间,重新发送它可能会比堆栈决定连接断开之前的预期更长,只有这样才会让你知道。
请参见此处:http://www.ietf.org/rfc/rfc2988.txt,此处:http://msdn.microsoft.com/en-us/library/ms819737.aspx等。
您已经习惯了有线网络,其中驱动程序可以通知更高级别的层连接已被物理断开。如果您要将有线网络配置为通过路由器路由,然后您故意将其设置为无法正确路由,那么您可能会看到类似的行为....