"Connected" UDP 套接字接收到 ICMP 端口无法访问

"Connected" UDP socket receives ICMP Port Unreachable

基于 UDP 是无连接协议的前提,我假设主机是启动还是关闭是无关紧要的。

然而,现在我正在做测试,我发现当我有 "connected" 我的 UDP 客户端套接字时,write 到那个套接字 returns 一个错误,因为服务器已发回 ICMP 端口无法访问错误 ..

"connecting" UDP 端口的目的(根据 Stevens Unix 网络编程)基本上是 缓存 条目来自路由 table,而不是为每个数据包创建一个新的路由,这应该具有性能优势。

但是,这个 ICMP 数据包导致我丢失了客户端套接字,这很烦人。

任何人都可以解释为什么会这样吗?有任何已知的解决方法吗?

我正在使用一个 3p java 库,它不考虑这个问题,只是断开连接,我可能不得不破解它才能重新连接,但在我这样做之前,我有点希望有我可以在 (Linux) 操作系统级别做一些事情来防止这种情况发生......所有对套接字选项等的调查都没有结果。

编辑

总而言之,这是不可能的,修复代码是唯一的方法。

似乎唯一的可能性是配置 iptables 以阻止 ICMP 响应,但要破解这个特定的螺母有点难。

嗯,UDP 位于 IP 之上。您收到的消息来自该层。 参见 https://en.wikipedia.org/wiki/User_Datagram_Protocolhttps://en.wikipedia.org/wiki/Internet_Control_Message_Protocol

所以从某种意义上说,这是 connection-less,您没有永久隧道,因此不能保证您的数据包按顺序到达,等等。或者,如果有错误,您不一定会立即识别。

但是您仍然需要能够连接到某些东西,首先。它只是发生在较低的层面上。

但内核仍会跟踪套接字,因此它可能会通知您它收到的 ICMP 数据包,比方说从沿途的路由器。重点是,ICMP在下一层。

更新:顺便说一下,我认为您可能会遇到相反的问题。你的路由器,或者任何介于两者之间的东西都可以忽略这样一个事实,即它不知道 connect 将数据包转发到哪里,只是静静地丢弃数据包,而不是用 ICMP 回复错误信息。

虽然您的 UDP 套接字不是严格意义上的 "connected",但进行 connect() 调用确实会为该套接字创建本地 "state"。

此状态不仅允许系统缓存当前路由条目的目的地,而且还意味着所有后续输出操作不需要指定目的地 - 它们将使用 connect() 呼叫。它还确保内核将丢弃不是来自 "connected" 方的发往您的套接字的入站数据包。

此连接状态还允许内核将与该套接字相关的错误(通过 ICMP 发出信号)传递给应用程序 - 未连接的套接字不会得到这些 - 它们是 "fire and forget"。

对于您在离线时指出的 log4j 代码,问题似乎完全出在用户 space 代码中。当 log4j UDPAppenderwrite 调用中收到 IOException 时,它只是单方面丢弃套接字,并且没有提供任何方法来检测该情况以便您可以修复它。