最近做的一个视频数据传输项目,发现密集型的数据发送,在接收端如果仅仅只是先接收固定长度的包头数据,按照包头数据的内容,获取后续数据的长度,再进行接收,这样做在本机上运行或许没有什么问题,一旦到了网络上就不行了。可能会出现错包的情况,也就是说,你认为你接收的是包头数据,但那不是真正的包头数据,因此,你对后续数据的接收就完全错位了。解决这个办法要加强对包头数据的检测,并且要在接收的过程中进行分包和并包的处理,也就是说把多余的数据缓存下来,和下一次接收的数据进行合并
int nRecvLen=0;
//接收数据
nRecvLen=recv(m_nFileSocket, chTempBuffer+m_nRecvSize, MAX_TEMP_BUFFER - m_nRecvSize, 0);
if( nRecvLen == SOCKET_ERROR )
{
return;
}
if(nRecvLen>0)
{
m_nRecvSize+=nRecvLen;
TRACE("recv buffer size %d /n",nRecvLen);
}
// TRACE("recv buffer size %d /n",m_nRecvSize);
//分包
int nIndex=0;
int nHeadPos=0;
int nHeadPosNow=0;
while((nHeadPos=SearchHeadPos(chTempBuffer+nIndex,m_nRecvSize-nIndex))>=0) //找到合适的包头数据
{
if(nHeadPos!=0)
{
nHeadPosNow=nHeadPos;
}
TRACE("HEAD POS %d /n",nHeadPos);
TLVSTREAMINFO* pStreamInfo=(TLVSTREAMINFO*)(chTempBuffer+nIndex+nHeadPos);
if( m_nRecvSize-nIndex-nHeadPos > pStreamInfo->udwBuffSize ) //是一个完整的数据包
{
/*
* 将数据先缓存起来,到达一定数值以后,再进行播放
*/
if( (MAX_VIDEO_BUFFER-m_nBufferIndex)> pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO))
{
//缓冲空间可以容纳新的数据包
memcpy(m_chVideoBuffer+m_nBufferIndex,chTempBuffer+nIndex+nHeadPos,pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO));
TLVSTREAMTag* streamTag=new TLVSTREAMTag;
streamTag->dwTimeTag=pStreamInfo->dwTimeTag;
streamTag->dwMillisTag=pStreamInfo->dwMillisTag;
streamTag->udwDataSize=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
streamTag->ucwIndexPos=m_nBufferIndex;
StreamList.push_back(streamTag);
//更新m_nBufferIndex的大小
m_nBufferIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
}
else
{
if( pStreamInfo->udwBuffSize > MAX_VIDEO_BUFFER || pStreamInfo->udwBuffSize < 0 )
{
return;
}
//缓冲空间不可以容纳新的数据包,再从头部开始缓存数据
m_nBufferIndex=0;
memcpy(m_chVideoBuffer+m_nBufferIndex,chTempBuffer+nIndex+nHeadPos,pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO));
TLVSTREAMTag* streamTag=new TLVSTREAMTag;
streamTag->dwTimeTag=pStreamInfo->dwTimeTag;
streamTag->dwMillisTag=pStreamInfo->dwMillisTag;
streamTag->udwDataSize=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
streamTag->ucwIndexPos=m_nBufferIndex;
StreamList.push_back(streamTag);
//更新m_nBufferIndex的大小
m_nBufferIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
}
nIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
m_nRecvCount++;
// TRACE("recv buffer number %d /n",m_nRecvCount);
//启动播放
if(m_nRecvCount>100)
{
if(!m_bTimerInit)
{
if(StreamList.size()>0)
{
TLVSTREAMTag* streamTag=StreamList.front();
if(streamTag)
{
//记录此帧的相关时间信息
m_StreamInfo.dwTimeTag=streamTag->dwTimeTag;
m_StreamInfo.dwMillisTag=streamTag->dwMillisTag;
//记录此帧的旧的us
lMilliSecondOld=streamTag->dwMillisTag;
//记录此帧的旧的ACE_TimeVal,便于相减计算时间间隔
time_old.tv_sec=streamTag->dwTimeTag;
time_old.tv_usec=streamTag->dwMillisTag;
//发送第一帧数据
m_pFilePlay->VideoPlayDataCome(m_nWnd,(char*)(m_chVideoBuffer+streamTag->ucwIndexPos+sizeof(TLVSTREAMINFO)),streamTag->udwDataSize-sizeof(TLVSTREAMINFO));
//设置初始的时间间隔40ms
m_Timer=timeSetEvent(40, 1,
(LPTIMECALLBACK) OneMilliSecondTimer,
(DWORD)this,TIME_PERIODIC);
//更新数据
StreamList.pop_front();
delete streamTag;
m_bTimerInit=true;
}
}
}
}
}
else
{
TRACE("HEAD POS %d /n",nHeadPos);
nHeadPos=0;
break;
}
}
if(nIndex>0)
{
if( nIndex + nHeadPosNow < m_nRecvSize)
{
//有数据全部没有处理完毕,将数据移动到缓冲区头部
memcpy(chTempBuffer,chTempBuffer+nIndex+nHeadPosNow,m_nRecvSize-nIndex-nHeadPosNow);
m_nRecvSize=m_nRecvSize-nIndex-nHeadPosNow; //更新位置
if(chTempBuffer[0]!='N' && chTempBuffer[1]!='J' && chTempBuffer[2]!='D' && chTempBuffer[3]!='V')
{
int nnnnn=0;
}
}
else
{
m_nRecvSize=0;
}
}
int nRecvLen=0;
//接收数据
nRecvLen=recv(m_nFileSocket, chTempBuffer+m_nRecvSize, MAX_TEMP_BUFFER - m_nRecvSize, 0);
if( nRecvLen == SOCKET_ERROR )
{
return;
}
if(nRecvLen>0)
{
m_nRecvSize+=nRecvLen;
TRACE("recv buffer size %d /n",nRecvLen);
}
// TRACE("recv buffer size %d /n",m_nRecvSize);
//分包
int nIndex=0;
int nHeadPos=0;
int nHeadPosNow=0;
while((nHeadPos=SearchHeadPos(chTempBuffer+nIndex,m_nRecvSize-nIndex))>=0) //找到合适的包头数据
{
if(nHeadPos!=0)
{
nHeadPosNow=nHeadPos;
}
TRACE("HEAD POS %d /n",nHeadPos);
TLVSTREAMINFO* pStreamInfo=(TLVSTREAMINFO*)(chTempBuffer+nIndex+nHeadPos);
if( m_nRecvSize-nIndex-nHeadPos > pStreamInfo->udwBuffSize ) //是一个完整的数据包
{
/*
* 将数据先缓存起来,到达一定数值以后,再进行播放
*/
if( (MAX_VIDEO_BUFFER-m_nBufferIndex)> pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO))
{
//缓冲空间可以容纳新的数据包
memcpy(m_chVideoBuffer+m_nBufferIndex,chTempBuffer+nIndex+nHeadPos,pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO));
TLVSTREAMTag* streamTag=new TLVSTREAMTag;
streamTag->dwTimeTag=pStreamInfo->dwTimeTag;
streamTag->dwMillisTag=pStreamInfo->dwMillisTag;
streamTag->udwDataSize=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
streamTag->ucwIndexPos=m_nBufferIndex;
StreamList.push_back(streamTag);
//更新m_nBufferIndex的大小
m_nBufferIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
}
else
{
if( pStreamInfo->udwBuffSize > MAX_VIDEO_BUFFER || pStreamInfo->udwBuffSize < 0 )
{
return;
}
//缓冲空间不可以容纳新的数据包,再从头部开始缓存数据
m_nBufferIndex=0;
memcpy(m_chVideoBuffer+m_nBufferIndex,chTempBuffer+nIndex+nHeadPos,pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO));
TLVSTREAMTag* streamTag=new TLVSTREAMTag;
streamTag->dwTimeTag=pStreamInfo->dwTimeTag;
streamTag->dwMillisTag=pStreamInfo->dwMillisTag;
streamTag->udwDataSize=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
streamTag->ucwIndexPos=m_nBufferIndex;
StreamList.push_back(streamTag);
//更新m_nBufferIndex的大小
m_nBufferIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
}
nIndex+=pStreamInfo->udwBuffSize + sizeof(TLVSTREAMINFO);
m_nRecvCount++;
// TRACE("recv buffer number %d /n",m_nRecvCount);
//启动播放
if(m_nRecvCount>100)
{
if(!m_bTimerInit)
{
if(StreamList.size()>0)
{
TLVSTREAMTag* streamTag=StreamList.front();
if(streamTag)
{
//记录此帧的相关时间信息
m_StreamInfo.dwTimeTag=streamTag->dwTimeTag;
m_StreamInfo.dwMillisTag=streamTag->dwMillisTag;
//记录此帧的旧的us
lMilliSecondOld=streamTag->dwMillisTag;
//记录此帧的旧的ACE_TimeVal,便于相减计算时间间隔
time_old.tv_sec=streamTag->dwTimeTag;
time_old.tv_usec=streamTag->dwMillisTag;
//发送第一帧数据
m_pFilePlay->VideoPlayDataCome(m_nWnd,(char*)(m_chVideoBuffer+streamTag->ucwIndexPos+sizeof(TLVSTREAMINFO)),streamTag->udwDataSize-sizeof(TLVSTREAMINFO));
//设置初始的时间间隔40ms
m_Timer=timeSetEvent(40, 1,
(LPTIMECALLBACK) OneMilliSecondTimer,
(DWORD)this,TIME_PERIODIC);
//更新数据
StreamList.pop_front();
delete streamTag;
m_bTimerInit=true;
}
}
}
}
}
else
{
TRACE("HEAD POS %d /n",nHeadPos);
nHeadPos=0;
break;
}
}
if(nIndex>0)
{
if( nIndex + nHeadPosNow < m_nRecvSize)
{
//有数据全部没有处理完毕,将数据移动到缓冲区头部
memcpy(chTempBuffer,chTempBuffer+nIndex+nHeadPosNow,m_nRecvSize-nIndex-nHeadPosNow);
m_nRecvSize=m_nRecvSize-nIndex-nHeadPosNow; //更新位置
if(chTempBuffer[0]!='N' && chTempBuffer[1]!='J' && chTempBuffer[2]!='D' && chTempBuffer[3]!='V')
{
int nnnnn=0;
}
}
else
{
m_nRecvSize=0;
}
}