UDP sendto上的ECONNREFUSED错误 [英] ECONNREFUSED errors on UDP sendto

查看:206
本文介绍了UDP sendto上的ECONNREFUSED错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写的应用程序遇到一些无法解释的行为 带有sendto()的UDP数据到多个端口(全部通过 socket(PF_INET, SOCK_DGRAM,0)),以使一组客户端读取过程受益.这些sendto()偶尔会意外地触发 ECONNREFUSED 错误.这是在macOS Sierra(10.12)系统上发生的,该系统的sendto(2)手册页甚至没有将 ECONNREFUSED 列为可能的错误.有趣的是,我有一个CentOS7系统(永远不会发生这些错误),其sendto(2)手册页引用了udp(7)手册页中记录的其他sendto()错误,而CentOS7 udp(7)页则显示:

I am experiencing some unexplained behavior with an app that is writing UDP data with sendto() to multiple ports (all opened with socket(PF_INET, SOCK_DGRAM, 0)) for the benefit of a set of client reading processes. These sendto()s occasionally and unpredictably trigger ECONNREFUSED errors. This is happening on a macOS Sierra (10.12) system whose sendto(2) manual page does not even list ECONNREFUSED as a possible error. Interestingly, I have a CentOS7 system (where these errors never occur) whose sendto(2) manual page references additional sendto() errors documented on the udp(7) manual page, and that CentOS7 udp(7) page says:

ECONNREFUSED

 No receiver was associated with the destination address. This
 might be caused by a previous packet sent over the socket.

(在macOS Sierra udp(4)页面上的任何地方都没有提到 ECONNREFUSED .) 我不知道CentOS7手册页是否与macOS相关, 但假设他们这样做了,上面关于sendto()的 ECONNREFUSED 解释在两点上令人困惑:

(ECONNREFUSED is not mentioned anywhere on the macOS Sierra udp(4) page.) I have no idea if the CentOS7 manual pages have any relevance to macOS, but assuming for a moment that they do, the above explanation of ECONNREFUSED with respect to sendto() is confusing on a couple of points:

首先,我所听到的有关UDP的一切都强调了它的无连接性质.那么,为什么sendto()会因为没有连接接收器而失败(或关联",如手册页所说,我指的是同一件事)? UDP的全部含义不是,如果您是一个谈话者,您只是轻描淡写,不在乎是否有人在听?这些CentOS7 udp(7)注释似乎确实适用于我的Sierra系统,因为当我运行绑定到这些端口并从这些端口读取的客户端进程时,我再也不会遇到问题,但是如果我启动 UDP编写器在读者运行之前,我会经常(但不总是) 看到这些错误.

First, everything I have ever heard about UDP emphasizes its connectionless nature. So, why would a sendto() fail because no receiver is connected (or 'associated', as the man page says, which I take to mean the same thing)? Isn't the whole point of UDP that if you are a talker, you just jabber away and don't care if anyone else is listening or not? These CentOS7 udp(7) comments do seem to apply to my Sierra system, however, because when I have client processes running which are bound to and reading from these ports I never have problems, but if I start the UDP writer before the readers are running I will often (but not always) see these errors.

第二,根据CentOS7 udp(7),谁能向我解释为什么? 文档,通过套接字发送的先前数据包可能不会导致 收件人与目标地址相关联?这使没有 对我完全没有感觉.某些数据报是否具有足够的毒性,以至于杀死读取它们的人?

Second, can anyone explain to me why, according to the CentOS7 udp(7) documentation, a previous packet sent over the socket could cause no receiver to be associated with the destination address? This makes no sense at all to me. Are some datagrams just so toxic that they kill whoever reads them?

我还要注意,除了在CentOS7上从未见过此问题外 在实际上(如果含糊)记录的地方,我也从未在Sierra之前的任何MacOS版本上体验过它,并且这段代码对我来说已经运行了很多年了.我仍然有一个El Capitan系统,无法在那里复制错误.

I should also note that, besides not ever seeing this problem on CentOS7 where it's actually (if vaguely) documented, I have also never experienced it on any MacOS release prior to Sierra, and this code has been running well for me for there many years. I still have one El Capitan system and cannot duplicate the errors there.

以下是有关我的应用的更多信息-请随时发表评论 关于PF_INET UDP,sendto()和 ECONNREFUSED 的上述一般性问题,或以下所述的我的应用程序的更具体细节.我已经有一个可用的解决方法(请参阅下文),但想更好地了解发生了什么.

Following is more information about my app -- please feel free to comment either on the above general questions about PF_INET UDP, sendto() and ECONNREFUSED or on the more specific details of my app as noted below. I have a usable workaround already (see below) but would like to better understand what is going on.

我的应用正在从各种来源(串行线路和/或UDP端口)读取数据,将其按摩成各种类型的重新格式化的输出消息,然后将这些消息写入多个预定义的连续编号(例如3000到3004)的UDP中少数可变数量的客户端(最多5个,但通常不超过3个或4个)读取位于同一IP地址的端口.每个客户端扫描我的应用程序的UDP输出端口的预定义列表,绑定到第一个可用端口,然后从该端口进行所有读取.不能保证我的编写器应用程序和多个阅读器进程的启动顺序是预先确定的(这里是我的问题的中心部分).我的应用正在每秒向每个输出端口写入一次消息,每个消息通常不超过大约80个字节(所有ASCII文本).

My app is reading data from various sources (serial lines and/or UDP ports), massaging it into reformatted output messages of various types and then writing those messages to multiple pre-defined consecutively numbered (e.g., 3000 through 3004) UDP ports at the same IP address to be read by a small and variable number of clients (limited to 5 but usually no more than 3 or 4). Each client scans the pre-defined list of my app's UDP output ports, binds to the first available port, and then does all its reading from that port. There is no guarantee in advance of the order in which my writer app and the multiple reader processes will be started (a central part of my problem here). My app is writing messages about once per second to each output port which are usually no more than about 80 bytes each (all ASCII text).

这些阅读器客户端可能正在(i)与我的应用程序相同的本地主机上运行,​​(ii)单个远程主机或(iii)本地网络上的其他远程主机上运行,​​因此我的编写器应用程序接受任意IPv4目标地址作为命令参数.假设我的编写器在主机192.168.1.LLL(本地主机)上运行,则最常用的目标地址将是:

These reader clients might be running on (i) the same local host as my app, (ii) a single remote host, or (iii) different remote hosts on the local network, so my writer app accepts an arbitrary IPv4 destination address as a command argument. Assuming my writer is running on host 192.168.1.LLL (the Local host), the most commonly used destination addresses will be:

  • 127.0.0.1
  • 192.168.1.LLL(本地主机的实际外部地址)
  • 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(可能导致错误的地址)来使事物私有.

Note that I see these errors ONLY when sending output to either 127.0.0.1 or to 192.168.1.LLL, the actual external address of the localhost. The errors never occur when I write to either a specific remote host 192.168.1.RRR or to the LAN's broadcast address 192.168.1.255. Is there supposed to be a difference between what happens with local PF_INET vs. remote PF_INET UDP writes? Maybe local writes have to be handled in a specific way within some local buffer which is subject to various constraints, whereas packets sent off-host are just scattered to the winds and whatever happens is considered beyond the reporting capacity of the local sendto()? Although I never see these errors when using the broadcast address 192.168.1.255 I prefer not to use that out of network politeness unless I know that my clients really are running on multiple remote hosts -- if everything is on one system I'd rather keep things private by using either of the strictly local addresses 127.0.0.1 or 192.168.1.LLL (which are the addresses that can lead to errors).

目前,我只是通过忽略所有 ECONNREFUSED sendto()错误来解决此问题.似乎我倾向于在启动应用程序后的几秒钟内获得它们,尽管从不在每个端口的第一个sendto()上,而且通常不在我的5个输出端口中的一个上(尽管产生错误的端口并不总是相同的) ).而且,在出现最初的错误之后,即使仍然没有读取器在运行,接下来几分钟的输出(我所看过的最长的时间)也不会出错.但是,这些错误是令人迷惑的,我希望对它们有更好的了解,以使我的代码尽可能健壮.我不将我的实际代码包含在这篇文章中,因为后者已经太长了,据我所知,该代码并没有什么不寻常的地方,但是如果有用的话,我可以将其单独发布.

For now I am working around this problem by just ignoring all ECONNREFUSED sendto() errors. It seems that I tend to get them within a few seconds of starting my app, although never on the first sendto() on each port and usually on only one of my 5 output ports (although the port generating the error is not always the same). And, after the initial errors, the next few minutes' worth of output (the longest I've ever watched) is error-free even though there are still no readers running. These errors are mystifying, however, and I would like to have a better understanding of them to make my code as robust as possible. I am not including my actual code in this post as the latter is already overly long and there's nothing unusual about the code as far as I can tell, but I can post it separately if that would be useful.

谢谢!

罗杰·戴维斯(Roger Davis), 大学夏威夷的

Roger Davis, Univ. of Hawaii

推荐答案

尽管在UDP层上,您也可以使用任意IP. RFC1122 ,第4.1.3.3节指出,IP层上的任何错误(导致发生ICMP错误的错误)必须将错误传播回应用程序层.如您在 RFC792 第3页中所见,代码3消息为Port Unreachable.

Whilst at the UDP layer you can jabber away to any IP. RFC1122, section 4.1.3.3, indicates that any errors at the IP layer (that cause ICMP errors to occur) must propogate the error back up to the application layer. As you can see in RFC792 page 3, a code 3 message is Port Unreachable.

因此,无法将IP数据包发送到端口127.0.0.1,将导致在应用程序层显示为ECONNREFUSED的icmp错误.据报告是异步的(因为icmp的回复超时),此时您可能已经发送了另一个udp数据包.

Hence the inability for an IP packet to be sent to a port of 127.0.0.1 will cause an icmp error manifested as ECONNREFUSED at the application layer. It's reported async (since icmp has timeouts for replies) and you may have send another udp packet by then.

为什么它在本地连接上发生更多?该数据包实际上从未离开内核,因此它可以在发送下一个udp数据包之前答复ICMP错误.在其他地址上,实际上必须将其放在网上.因此,您仍然可以得到错误,但是根据您的UDP发送速率,它们的出现频率会降低.同样,如果您通过网关发送,则网关可能会丢弃udp数据包.如果您的主机和远程主机之间存在防火墙,它可能还会丢弃icmp答复,或限制答复的返回率.

Why does it happen more on local connections? The packet doesn't actually ever leave the kernel hence it can reply to the ICMP error before the next udp packet is sent. On the other addresses, it actually has to be put on the wire. So you can still get the errors but they will be less frequent depending on your UDP send rate. Also if your sending through a gateway the gateway might just drop the udp packet. If there's a firewall between your host and the remote host, it might also drop the icmp reply, or limit the return rate of the reply.

解决该错误,如果确实得到ECONNREFUSED,则说明没有主机具有该IP,或者没有侦听该端口的主机.无论哪种方式,发送都毫无意义.

Addressing the error, if you do get ECONNREFUSED, you know there's either no host with that IP or nothing listening on that port. Either way, it's pointless still sending.

这篇关于UDP sendto上的ECONNREFUSED错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆