本人在做一个视频传输的程序,目的是将客户端jpeg格式的视频发送到服务器端。发送的过程如下:
1、客户端取得一帧图像的大小,将大小数据(int型,占4 byte)发送到服务器端。
2、在发送图像大小后开始发送图像数据。
采用的是阻塞式的发送与接收,没有标记帧头与帧尾,发送端只管按照发送的过程发送,接收端按照相应的过程接收,一帧发完延迟一会发下一帧。
发送代码片段如下:#define BUF_LENS 2048
……
send(slisten, &iJpegSize , sizeof(&iJpegSize ), 0);//获得图像大小
while(1)
{
iSend = send(slisten, JpegBuf + iSendCnt , BUF_LENS, 0);
Sleep(1);
iSendCnt += iSend;
if(iSendCnt == iJpegSize)//发送完成
{
break;
}
……
}接收代码片段如下:#define BUF_LENS 2048
while(1)
{
iRecv = recv(slisten, buffer , BUF_LENS, 0);
if(!m_IsGetSize)
{
iJpegSize = GetJpegSize(buffer);//由char转换得到int的图像大小数据
m_IsGetSize = TRUE;               
}
else
{
iRecvCnt += iRecv;
if(iRecvCnt == iJpegSize)
{
break;
}
}
}测试结果:大部分时候发送接收都没问题,能够正常接收图像大小和数据。但是有时候接收不到图像的大小,导致程序崩溃。在一番测试调查后发现正常情况下第一个接收的iRecv的值是等于4的(也就是一个int的大小,即send(slisten, &iJpegSize , sizeof(&iJpegSize ), 0); 这段程序发送的数据,存储了图像大小的数据),但是在程序崩溃的情况下第一个接收的iRecv的值不是等于4,
而是等于2048(即iSend = send(slisten, JpegBuf + iSendCnt , BUF_LENS, 0); 这段代码发的数据),在这种情况下iRecv等于4的会被延后,可能是第3个,也可能是第10个。我的疑惑就是TCP不是顺序接收数据的吗?为什么会出现先发的socket后到,后发的先到的情况?而且按理来说网络发送会出现合并包、分包的情况,就是4 byte的数据很可能会和后面的数据合并成一个包一起发送,但是我这里却还是会收到4 byte这个数据包,有高手能够解释下吗?谢谢

解决方案 »

  1.   

    你的数据包要定义包头信息,就是要求你定义传输协议。例如每个数据包的前4个字节定义命令ID:如ID-A:长度,ID-B:帧数据头,ID-C:帧数据,ID-D:帧数据尾。当收到ID-A的命令后,并回执成功命令后才开始帧数据的发送。还有就是你一帧数据就几百K,完全没必要分散发,直接组装个几M的数据报一次丢过去,或则你直接一帧一帧的发送,但是每一帧前4个字节存放该帧长度,在接收数据的时候分两次接受,第一次接受4个字节,二次接受指定长度。还有就是你问题的关键了:TCP传输确实收数据可能会乱序的收到数据包,但是这顺序整合的工作TCP自己做了,你调用收到的数据一定是顺序的。你出现的问题应该是你client端代码的问题,你一来就接收2048的长度就是出问题的关键,应该只收4个字节的长度。实际情况是你client接受的第一包数据可能是你server端发送的第一包长度数据4个字节加上第二包数据的前2044个字节的数据。我想,如果你把服务端的那个sleep(1)代码取消掉,你个问题复现概率将直线上升。