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