基于UDP协议的recvfrom函数无法获取一个完整的UDP包,该如何解决

基于UDP协议的recvfrom函数无法获取一个完整的UDP包

void RZAgent::RecvPeerData(WAIT_MODE _eWaitMode /* = ENUM_SYN */)
{
pNetConn->WaitForPeerResponse(_eWaitMode);
pNetConn->RecvDataFromPeer();
}

利用这个函数接收对端的数据,首先等待对端响应,响应函数中主要是利用select等待套接字是否可读,如下

::select(maxFd+1, &readySet, NULL, NULL, ptv)

并且由于接收操作是放在一个单独的线程里的,所以使用的是阻塞模式等待数据到达,一旦数据到了,那么我就开始接收
RecvDataFromPeer();这个函数中封装了recvfrom函数,然后将收到的数据放到本地缓冲区中

现在的问题是:每次调用RecvDataFromPeer();也即recvfrom,用抓包工具看完整的一个UDP数据包如下

 80 C8 00 06 40 A5 8C 19  D7 5E 18 68 52 2D 0E 56   ....@... .^.hR-.V 
6A 9F AA 5F 00 00 00 01  00 00 00 26 81 CA 00 06   j.._.... ...&.... 
40 A5 8C 19 01 0E 51 54  53 53 31 34 30 34 32 37   @.....QT SS140427 
39 32 37 32 00 00 00 00  81 CC 00 06 40 A5 8C 19   9272.... ....@... 
71 74 73 69 00 00 00 00  00 00 00 02 61 74 00 04   qtsi.... ....at.. 
00 00 00 14

但是每次从recvfrom返回时我只能接收到80 C8这2个字节。
所以有没有这样一种可能,当前协议栈正在接收一个UDP数据包的时候,还没全部收完,然后进程切换,由于本地使用同步模式阻塞在这个套接字上,select检测到当前套接字上数据可读,然后直接返回,再调用recvfrom返回了整个包的一部分?

PS:对端服务器发送的是一个几十M的文件,每次切成一个块,然后使用UDP不停地发。
------解决方案--------------------
我是真心不懂为啥都喜欢用字符串保存二进制数据
要说新手图简单吧,也有不少写这种代码的人水平比我更好
要说高手用得好吧,为啥又犯一些低级错误呢

std::string(rBuffer)
std::string是字符串容器,其构造函数按C风格字符串解释输入指针指向的内存,最终调用的是strlen函数
你收到的数据包第三个字节就是0,它当然只解析前两个字节
------解决方案--------------------
引用:
Quote: 引用:

recvfrom有没有调用错了,UDP方式的话,包不完整是会丢弃整包数据的,而且从你抓包的情况来年确实是整包数据都到了

谢谢回复,我贴下RecvDataFromPeer的代码:

std::string RZUdpConn::RecvDataFromPeer()
{
if (!SocketValid())
Log::ERR("Can not receive data, Please BuildConnection first.\n");

::memset(rBuffer, 0, ulBufSize);
#ifdef WIN32
struct sockaddr_in lPeerAddr;
::memset(&lPeerAddr, 0, sizeof(sockaddr_in));
int iSize = sizeof(lPeerAddr);
if (::recvfrom(iSockFile, rBuffer, ulBufSize, 0,
(sockaddr*)&lPeerAddr, &iSize) == SOCKET_ERROR)
Log::ERR("Platform SDK \'recvfrom\' called failed.\tError Code: %d\n", WSAGetLastError());
#endif
return std::string(rBuffer);
}

就是简单的对recvfrom的封装,没看出有什么问题啊

之前搜了许多资料,知道在收udp包时,如果物理层校验通过,发现数据传输未出错,那么会传给IP层,否则就是整包丢弃。所以recvfrom调用要么收不到,要么收到一个完整的,而上面这种情况根本不会出现。但打印调试信息,发现确实收不全,我也是无奈了。
本来要做一下解析的,因为收到的包含有8个字节的头部,如果少于8个字节说明包的格式不正确,就会直接丢弃,现在在每次调用返回2个字节,根本不做解析就直接丢弃,在解析模块里下了断点,完全不会陷进去。

buf不一定是字符串, 不能直接std::string(buf),试试std::vector<char>
------解决方案--------------------
你得把recvfrom的返回值也带上,这才是真正到的接收数据的长度