如何在向非阻塞Socket发送数据时模拟EAGAIN或EWOULDBLOCK错误?
模拟非阻塞Socket send返回EAGAIN并触发EPOLLOUT的测试方法
嗨,这个测试场景我做网络编程的时候也折腾过,分享几个靠谱的模拟方法,帮你把重发代码的测试覆盖到:
方法一:缩小发送缓冲区强制填满
这是最直接的代码层面模拟方式:
- 在创建非阻塞Socket后,调用
setsockopt将发送缓冲区SO_SNDBUF设置为极小值(比如128字节):int buf_size = 128; setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)); - 随后尝试发送远大于缓冲区容量的数据(比如一次性发1024字节):第一次
send可能会返回部分成功写入的字节数,继续调用send就会触发EAGAIN/EWOULDBLOCK错误。 - 此时注册
epoll_ctl监听该Socket的EPOLLOUT事件,epoll很快就会触发该事件(内核缓冲区的可用空间变化会触发通知),你就能测试重发逻辑了。
方法二:用本地回环Socket配合接收端不读取数据
利用本地socket的特性,人为让发送缓冲区饱和:
- 创建一对本地Socket(可以用
socketpair创建AF_UNIX域的socket对,或者让客户端连接本地的TCP服务器)。 - 让接收端完全不调用
recv读取数据,发送端以非阻塞模式持续发送大体积数据。 - 当发送端的
send返回EAGAIN/EWOULDBLOCK后,向epoll注册EPOLLOUT事件。此时只要让接收端读取少量字节(比如调用一次recv读几个字节),发送端的epoll就会立刻触发EPOLLOUT,触发你的重发流程。
方法三:用流量控制工具模拟(适合更真实的网络场景)
如果想模拟更接近真实网络的阻塞情况,可以用Linux的tc工具限制网卡的发送速率:
- 比如在本地回环网卡上设置极低的发送带宽:
tc qdisc add dev lo root tbf rate 1kbit burst 100b latency 70ms - 此时发送端快速发送大量数据时,内核缓冲区会很快被填满,
send就会返回EAGAIN,之后当带宽有空闲时,epoll会触发EPOLLOUT事件。测试完成后记得删除规则:tc qdisc del dev lo root
测试注意事项
- 注意区分epoll的边缘触发(EPOLLET)和水平触发模式:如果是边缘触发,要确保在
EPOLLOUT事件触发时尽可能发送数据直到再次返回EAGAIN;如果是水平触发,要避免陷入循环发送的忙等状态。 - 测试完成后记得恢复Socket的缓冲区设置,避免影响其他测试逻辑。
内容的提问来源于stack exchange,提问作者Joseph Conrad
相关产品推荐
相关产品推荐

