是否有Sockopt或其他选项可忽略UDP连接中的'connection refused'错误?
已连接UDP套接字忽略ICMP端口不可达报错的实现方案
返回Connection refused的本质是:UDP本身是无连接协议,connect操作仅仅是让操作系统内核绑定了该套接字对应的远端地址、过滤非对应远端的报文,同时会将后续收到的对应远端的ICMP异步错误缓存,在调用该套接字的IO操作(send/recv)时返回给应用层。该场景下UDP报文实际上已经成功发送到网络中,返回的错误是后续异步到达的ICMP端口不可达通知,并非报文未发送成功。
可行解决方案
- 方案1:应用层自行处理错误(跨平台通用,最推荐)
无需修改任何系统内核参数,只需在调用send后做错误判断即可:如果返回值小于0且errno为ECONNREFUSED,直接忽略该错误,返回本次尝试发送的字节数即可。该方案完全符合UDP无连接的语义,兼容性最高。 - 方案2:Linux平台通过套接字选项禁用ICMP错误上报
在套接字创建后、发送报文前,设置IP_RECVERR选项为0,禁用ICMP扩展错误上报,操作系统就不会将异步ICMP错误映射为send调用的错误返回:int disable_recverr = 0; setsockopt(sock_fd, IPPROTO_IP, IP_RECVERR, &disable_recverr, sizeof(disable_recverr)); - 方案3:BSD/macOS平台通过套接字选项禁用ICMP错误上报
对应平台可以设置SO_UDPNOICMP选项,禁止内核将UDP对应的ICMP错误上报给应用层:int enable_no_icmp = 1; setsockopt(sock_fd, IPPROTO_UDP, SO_UDPNOICMP, &enable_no_icmp, sizeof(enable_no_icmp));
修改套接字选项的方案依赖对应操作系统内核的特性支持,部分裁剪版内核可能不支持相关选项,优先推荐使用应用层错误处理的方案。
内容的提问来源于stack exchange,提问作者Liam Kelly
相关产品推荐
相关产品推荐

