非阻塞模式下recv返回EAGAIN且tcpdump显示内核无丢包的原因
非阻塞UDP recv持续返回EAGAIN、tcpdump无内核丢包的原因
首先明确核心前提:tcpdump输出的0 packets dropped by kernel仅统计内核向tcpdump专属捕获缓冲区拷贝报文时的丢包,不代表网卡收到的匹配报文已经被内核递送到你的业务UDP socket接收队列,该统计和业务socket的接收状态无关。
可能的故障原因如下:
- Socket未正确绑定地址与端口
如果UDP socket未调用bind()绑定到报文的目标端口,或是绑定的IP地址与报文的目标IP不匹配(例如绑定了127.0.0.1,但报文目标是网卡的公网/局域网IP),内核不会将对应报文放入该socket的接收队列,调用recv就会持续返回EAGAIN。 - 未配置广播/多播对应socket选项
如果捕获到的报文是广播类型,当前socket未开启SO_BROADCAST选项;如果是多播类型,当前socket未加入对应的多播组,内核也不会将这类报文递送到当前socket。 - UDP socket提前调用了connect,过滤了非匹配来源报文
如果你为UDP socket调用过connect()固定了对端的地址和端口,内核会自动丢弃所有来源地址、端口不匹配的报文,这类报文也不会进入socket接收队列。 - 防火墙/Netfilter规则拦截了报文
iptables等防火墙规则如果配置在路由后、socket接收前的链上执行DROP动作,报文会被netfilter模块直接拦截,不会送到业务socket。此时tcpdump在网卡入口层可以抓到报文,但socket接收队列无数据,同时这类丢包不会统计到tcpdump的丢包计数中。 - 持有错误的文件描述符
确认调用recv的fd确实是目标UDP socket的文件描述符,存在fd被意外关闭、复用,或是指向其他类型资源(如TCP socket、普通文件)的可能,也会导致读取不到数据。
内容的提问来源于stack exchange,提问作者betteroutthanin
相关产品推荐
相关产品推荐

