我在使用正在写入的应用程序时遇到一些无法解释的行为
使用 sendto() 向多个端口发送 UDP 数据(所有端口均使用套接字(PF_INET,
SOCK_DGRAM, 0))为了一组客户端读取进程的利益。这些 sendto() 偶尔会不可预测地触发经济拒绝错误。这种情况发生在 macOS Sierra (10.12) 系统上,其 sendto(2) 手册页甚至没有列出经济拒绝作为一个可能的错误。有趣的是,我有一个 CentOS7 系统(这些错误永远不会发生),其 sendto(2) 手册页引用了 udp(7) 手册页上记录的其他 sendto() 错误,并且 CentOS7 udp(7) 页面显示:
经济拒绝
No receiver was associated with the destination address. This
might be caused by a previous packet sent over the socket.
(经济拒绝macOS Sierra udp(4) 页面上的任何地方都没有提及。)
我不知道 CentOS7 手册页与 macOS 是否有任何相关性,
但假设他们这样做了,上面的解释经济拒绝关于 sendto() 在以下几点上令人困惑:
首先,我所听到的有关 UDP 的一切都强调它的无连接性质。那么,为什么 sendto() 会因为没有连接接收器(或“关联”,如手册页所述,我认为是同一件事)而失败? UDP 的全部意义不就是如果你是一个说话者,你就只是喋喋不休,不在乎其他人是否在听?然而,这些 CentOS7 udp(7) 注释似乎确实适用于我的 Sierra 系统,因为当我运行绑定到这些端口并从这些端口读取数据的客户端进程时,我永远不会遇到问题,但如果我启动
UDP writer 在读者运行之前我会经常(但不总是)
看到这些错误。
其次,根据 CentOS7 udp(7),任何人都可以向我解释为什么吗?
文档,通过套接字发送的前一个数据包可能会导致不
接收者为与目标地址相关联?这使得不
对我来说毫无意义。是否有些数据报的毒性如此之大,以至于读它们的人都会被杀死?
我还应该注意到,除了在 CentOS7 上从未见过这个问题之外
在它实际(如果模糊)记录的地方,我也从未在 Sierra 之前的任何 MacOS 版本上经历过它,并且这段代码多年来一直运行良好。我仍然有一个 El Capitan 系统,无法重复那里的错误。
以下是有关我的应用程序的更多信息 - 请随时发表评论
关于上述有关 PF_INET UDP、sendto() 和的一般问题经济拒绝或我的应用程序的更具体细节,如下所述。我已经有了一个可用的解决方法(见下文),但想更好地了解发生了什么。
我的应用程序正在从各种来源(串行线路和/或 UDP 端口)读取数据,将其整理为各种类型的重新格式化输出消息,然后将这些消息写入多个预定义的连续编号(例如,3000 到 3004)的 UDP 端口相同的 IP 地址由少量且可变数量的客户端(限制为 5 个,但通常不超过 3 或 4 个)读取。每个客户端都会扫描我的应用程序的 UDP 输出端口的预定义列表,绑定到第一个可用端口,然后从该端口进行所有读取。无法提前保证我的编写器应用程序和多个读取器进程的启动顺序(这里是我的问题的核心部分)。我的应用程序大约每秒向每个输出端口写入一次消息,每个输出端口通常不超过 80 个字节(均为 ASCII 文本)。
这些读取器客户端可能在 (i) 与我的应用程序相同的本地主机上运行,(ii) 单个远程主机,或 (iii) 本地网络上的不同远程主机上运行,因此我的编写器应用程序接受任意 IPv4 目标地址作为命令参数。假设我的编写器在主机 192.168.1.LLL(本地主机)上运行,最常用的目标地址将是:
- 127.0.0.1
- 192.168.1.LLL(localhost的实际外部地址)
- 192.168.1.RRR(同一 LAN 上的某些远程主机)
- 192.168.1.255(多个远程主机上的读者的本地广播)
请注意,我仅在将输出发送到 127.0.0.1 时看到这些错误
或 192.168.1.LLL,本地主机的实际外部地址。这
当我写入特定的远程主机时,永远不会发生错误
192.168.1.RRR 或 LAN 的广播地址 192.168.1.255。有没有
本地 PF_INET 与远程 PF_INET UDP 写入之间应该有什么区别?也许本地写入必须在某些本地缓冲区中以特定方式进行处理,该缓冲区受到各种限制,而离开主机发送的数据包只是散落在风中,并且发生的任何情况都被认为超出了本地 sendto() 的报告能力?尽管我在使用广播地址 192.168.1.255 时从未看到这些错误,但出于网络礼貌,我宁愿不使用该地址,除非我知道我的客户端确实在多个远程主机上运行 - 如果所有内容都在一个系统上,我宁愿保留通过使用严格本地地址 127.0.0.1 或 192.168.1.LLL(这些地址可能会导致错误)来实现私有。
现在我正在通过忽略所有来解决这个问题经济拒绝sendto() 错误。看来我倾向于在启动应用程序后的几秒钟内获取它们,尽管从来没有在每个端口上的第一个 sendto() 上获取它们,并且通常只在我的 5 个输出端口中的一个上获取它们(尽管生成错误的端口并不总是相同) )。而且,在最初的错误之后,接下来几分钟的输出(我见过的最长的时间)是没有错误的,即使仍然没有读者在运行。然而,这些错误令人费解,我想更好地理解它们,以使我的代码尽可能健壮。我没有在这篇文章中包含我的实际代码,因为后者已经太长了,而且据我所知,代码没有什么异常,但如果有用的话,我可以单独发布它。
Thanks!
罗杰·戴维斯,
大学。夏威夷的