一个关于UDP socket服务端接收长度不正确的问题

2019-07-13 07:32发布

最近项目需要实现一个通过UDP协议和远端服务平台通讯的需求,简要描述如下:
本端为嵌入式linux路由器(udp客户端,linux C编码),远端为租用的阿里云服务器(udp服务端,java编码),
通信协议为UDP,本端会定时向远端服务器发送消息。

在实现和调试过程中发现一个问题:
1)将远端服务程序放在实验室pc机上调试没有问题,即“路由器-PC”交互正常。
2)将远端服务程序放至阿里云服务器上运行,结果服务端收到的udp消息会多出4个字节,偶尔还会多出6个,多出的字节是 EF BF 之类的。
3)在远端服务器通过tcpdump抓包发现,tcpdump抓到的udp报文长度是正确的,并没有多出4个字节。
4)在检查并尝试字节序、字节对齐等问题后,仍然没有找到问题的原因。
5)最后,想到把消息中传输数值的地方,全部转换为字符串方式传输,结果问题没了,但是原因还无法确定。
6)在网上搜到一篇类似问题的帖子,但是,没有给出最终解决方案,链接如下:
       http://bbs.csdn.net/topics/370180910
   
1. 发现问题的代码实现,即消息传输中有数值
unsigned char tmpBuf[DIAG_NOTIFY_LEN] = {0}; unsigned short usCrc = 0, uslen = 0; memset(tmpBuf, 0, DIAG_NOTIFY_LEN); ((NotifyHeader *)(tmpBuf))->HeaderFlag = htons(DIAG_MSG_HEADER); ((NotifyHeader *)(tmpBuf))->MsgType = htons(DIAG_NOTIFY_MSG); ((NotifyHeader *)(tmpBuf))->SeqNum = htons(g_usLastSeq); ((NotifyHeader *)(tmpBuf))->DataLen = htons(strlen(macBuf)); sprintf(tmpBuf+sizeof(NotifyHeader), "%s", macBuf); uslen = sizeof(NotifyHeader) + strlen(macBuf); usCrc = CRC16(tmpBuf, uslen); *(tmpBuf+uslen) = (usCrc & 0xff00) >> 8; *(tmpBuf+uslen+1) = usCrc & 0x00ff; if(0 > sendto(g_diagSockFd, tmpBuf, uslen+DIAG_CRC_LEN, 0, g_pstAddrInfo->ai_addr, g_pstAddrInfo->ai_addrlen)) { perror("diag_notify [sendto]"); }   
    关键数据结构定义为:
typedef struct tagNotifyHeader { unsigned short HeaderFlag; unsigned short MsgType; unsigned short SeqNum; unsigned short DataLen; }NotifyHeader;    考虑到字节对齐问题,定义时特意注意了一下保证数据结构的字节对齐。
    另外,为了彻底排除字节对齐的影响,还尝试了单个字节逐一赋值的方式,即
*tmpBuf = (DIAG_MSG_HEADER & 0xFF00) >> 8; *(tmpBuf+1) = DIAG_MSG_HEADER & 0x00FF; ......    结果问题依旧存在,后来想到全部转换为字符串的方式传输(如下),结果服务器端接收ok。

2. 将消息中的数值全部转换为字符串方式传输,服务器端接收正常
unsigned char tmpBuf[DIAG_NOTIFY_LEN] = {0}; unsigned short usCrc = 0, uslen = 0; memset(tmpBuf, 0, DIAG_NOTIFY_LEN); uslen = sprintf(tmpBuf, "%x", DIAG_MSG_HEADER); uslen += sprintf(tmpBuf+uslen, "%x", DIAG_NOTIFY_MSG); uslen += sprintf(tmpBuf+uslen, "%4x", g_usLastSeq); uslen += sprintf(tmpBuf+uslen, "%4x", strlen(macBuf)); uslen += sprintf(tmpBuf+uslen, "%s", macBuf); usCrc = CRC16(tmpBuf, uslen); uslen += sprintf(tmpBuf+uslen, "%4x", usCrc); if(0 > sendto(g_diagSockFd, tmpBuf, uslen, 0, g_pstAddrInfo->ai_addr, g_pstAddrInfo->ai_addrlen)) { perror("diag_notify [sendto]"); }结果问题虽然不出现了,但是原因没有找到,目前怀疑会不会与字符集有关。    
还请各位大虾帮忙看看有没有遇到过类似的问题,或者帮忙指出该问题的原因到底在哪?