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.csdn.net/xclshwd/article/details/102985388文章来源:https://www.toymoban.com/news/detail-661317.html
https://www.jianshu.com/p/7ecd6a5530ce文章来源地址https://www.toymoban.com/news/detail-661317.html
到了这里,关于Linux 非阻塞方式Send函数报“Resource temporarily unavailable“优化方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!