Linux - send 出现 Resource temporarily unavailable

1.前言

主机和AI设备通讯时候,通过send发送小数据,发送和接受都正常。可是发送YUV数据时候,一帧720P数据大概1.3M左右,发送时候就会报错Resource temporarily unavailable错误,只发送了一帧的部分数据,导致该帧数据不完整,无法使用。通过错误码查找,是由于发送缓存池满导致的。

2.代码

int Send(int handle, unsigned char *buf, int len,
        int flags, const int selectSec, const int selectUsec)
{
	int		sendtotal	= -1;
	int		sendlen	= 0;
	fd_set wset;
	struct timeval tv;
	
	FD_ZERO(&wset);
	FD_SET(handle, &wset);
	tv.tv_sec = selectSec / 1000000;
	tv.tv_usec = selectUsec % 1000000;
	
	int	result	= select(handle + 1, NULL, &wset, NULL, &tv);
	if ( result > 0)
	{
		if (FD_ISSET(handle, &wset))
		{
			sendtotal		= 0;
			while(sendtotal < len)
			{
				sendlen	 = send(handle, (buf + sendtotal), (len - sendtotal) , flags);
				if(sendlen <= 0)
				{
					perror("-----[send]----:");
					return -1;
				}
				sendtotal	+=  sendlen;
			}
		}
	}
	else
	{
		perror("-----[select]----:");
	}

	return sendtotal;
}

 

3.解决方法

      在阻塞模式下,send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调用recv);
      在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,如果缓存区可用空间不够,则尽能力的拷贝,返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.

     当客户通过Socket提供的send函数发送大的数据包时,就可能返回一个EGGAIN的错误。该错误产生的原因是由于send函数中的size变量大小超过了tcp_sendspace的值。tcp_sendspace定义了应用在调用send之前能够在kernel中缓存的数据量。当应用程序在socket中设置了O_NDELAY或者O_NONBLOCK属性后,如果发送缓存被占满,send就会返回EAGAIN的错误。

解决方法:

     1)在调用send前,在setsockopt函数中为SNDBUF设置更大的值

         intopt=SO_REUSEADDR;
        setsockopt(tcp_client_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
          opt = 512*1024;
          int optlen = sizeof(int);
          setsockopt(tcp_client_sock,SOL_SOCKET,SO_SNDBUF,&opt,sizeof(int));
          getsockopt(tcp_client_sock,SOL_SOCKET,SO_SNDBUF,&opt,&optlen); 
  2).使用write替代send,因为write没有设置O_NDELAY或者O_NONBLOCK

代码如下:

采用write并分包发送策略 

int Send_YUV_Slice_Packet(int socket, unsigned char *data, unsigned int len)
{
	/**分包策略省略*/
	{
		
		while (hasSndLen<packetlen)
		{
			
			nRet = write(socket, sendBuf+hasSndLen, needSndLen);
			if (nRet <= 0)
			{
				int		errNo = errno;

				if ((nRet < 0) && ((errNo == EINTR) || (errNo == EAGAIN)))
				{
					usleep(10*1000);/**发送区为满时候循环等待,直到可写为止*/
					continue;
				}
				else
				{
					printf("write Err, nRet=%d, errno=%d \n", nRet, errNo);
					return -1;
				}
			}
			else
			{
				hasSndLen += nRet;
				if (hasSndLen < packetlen)
				{
					needSndLen = packetlen - hasSndLen;
					usleep(10*1000);
				}
			}
		}	
	}

	return 0;
	
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值