Linux 非阻塞方式Send函数报“Resource temporarily unavailable“优化方法

文章介绍了在Linux环境下,使用非阻塞模式的send函数发送大文件(如图片)时,如何处理资源暂时不可用的情况。当TCP缓存不足时,send函数可能会返回EAGAIN错误。作者提供了一个检查TCP连接是否断开的函数checkTcpConn,并提出通过记录发送失败的持续时间来判断是否因网络异常导致的连接断开,从而实现超时退出,避免程序阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

linux下将Send发送函数设置为非阻塞方式【如,send(socket, data + (dataLen - leftLen), leftLen, MSG_DONTWAIT)】,然后使用send向服务器发送大量数据(如图片,上百k数据);

非阻塞方式含义:就是将待发送数据拷贝到底层协议栈缓存区,不需要对端确认数据已接收。如果缓存区可用空间够或者不够,返回成功拷贝的大小。如缓存区可用空间为0,则返回-1,同时错误码errno为EAGAIN(含义为再次尝试),错误原因为Resource temporarily unavailable。

背景:

项目中会向服务器上报图片等大量数据,因底层协议buf缓存小(小于需要上报的数据),使用非阻塞Send函数的数据正常上报时也会出现资源不可用"Resource temporarily unavailable"的正常现象;

当网络异常时,底层buf被沾满后无法释放导致一直出现资源不可用的错误,但此时又无法检测到TCP链接断开,会引起代码一直阻塞在数据上报流程中无法退出

/********检测TCP链接是否断开***********/
long checkTcpConn(long socket)
{
    long lRet = 0;
    struct tcp_info info;
    int optlen = sizeof(struct tcp_info);
    lRet = getsockopt(Socket, IPPROTO_TCP,TCP_INFO, &info, (socklen_t *)&optlen);
    if (lRet < 0  || info.tcpi_state != TCP_ESTABLISHED)
    {
        //Tcp链接已断开
        return -1;
    }
     return 0;
}

优化方法:超时退出

记录大量数据正常上报完成时,出现资源不可用"Resource temporarily unavailable"的时长 normalTime => 根据时间来区分是否链接异常,进而可及时退出数据上报流程避免阻塞;

long sendDataToServer(long dataLen, char *data)
{
    long leftLen = dataLen;
    long sendLen = 0;
    long curTime = 0;
    long lastSendFailTime = 0;
    #define SEND_FAIL_TIMEOUT_THR (3)    //大于上述的normalTime
    
    while(leftLen > 0)
    {
        sendLen = send(socket, data + (dataLen - leftLen), leftLen, MSG_DONTWAIT);
    
        if(sendLen <= 0)
        {
            if(errno != EAGAIN && (errno != WSAEWOULDBLOCK) && errno != EINTR)  
            {    
                printf("send data fail, error[%s]", strerror(errno));
                return -1;
            }  
    
            if(-1 == checkTcpConn(socket))
            {
                //检测到TCP链接断开
                return -1;
            }
    
            if(errno == EAGAIN)
            {
                //获取当前时间,单位s
                curTime = getUtcTime();
                if(0 == lastSendFailTime)
                {        
                    lastSendFailTime = curTime;
                }
                else if(curTime - lastSendFailTime >= SEND_FAIL_TIMEOUT_THR)
                {
                    //认为 TCP链接断开,退出循环
                    return -1;
                }
            }
        }
        else
        {
            leftLen -= sendLen;
        } 
    }
    return 0;
}

附,参考文档链接:

https://blog.youkuaiyun.com/xclshwd/article/details/102985388

https://www.jianshu.com/p/7ecd6a5530ce

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值