自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:


1.问题描述

  socket通讯TCP协议虽然是稳定的通讯,但是也会出现丢包的现象,而且会出现一个数据包分几次发送的情况。所以需要用一个缓冲区去缓存数据,并且判断是不是一个完整的包。等接收到一个完整的数据包,然后再去处理解析。

2.解决方案

先要定一个特殊字符串,比如&#@!,这样四个字节的协议头,在你的通讯报文中绝对不会出现。然后在丢包之后,通过查找这四个字节的协议头,找到包开始的地方,将数据缺失的包过滤掉。找到这个协议头之后再去解析数据的长度,解析完数据数据长度,在缓存这个长度的包数据进行解析。一般是xml、json等格式的字符串字节流。只要读取指定长度的数据,进行数据解析即可。

ios socket丢包怎么解决 socket丢包,粘包_字符串

 

 3具体实现代码

结构定义

#define MAX_BUFFER_LENGTH        (10*1024)
#define PROTOCOL_HEAD_LEN        12    //FAD 报文头长度

typedef struct
{
    char gRecvBuff[TCP_RECV_DATA_LEN];
    HPR_INT32 iBuffLen;
}BUFFER_INFO;


BUFFER_INFO m_stRecvBuf;//一次接收数据的缓存区
char        m_pDataBuff[MAX_BUFFER_LENGTH];//每次接收的数据都放入这个缓冲区,空间更加,不断的处理接收
HPR_INT32   m_iDataLen;//总的数据长度
HPR_INT32   m_iOneFameLen;//一个数据包的数据长度,包括协议头、包长度和包数据

函数算法实现

HPR_INT32 CCuItem::ParseData(HPR_ULONG NumberOfBytes)
{
    HPR_UINT16 iRetVal = HPR_ERROR;
    if( NumberOfBytes<0)
    {
        LOG_ERROR("ParseDataFromUtdu Point is NULL");
        return iRetVal;
    }
    LOG_INFO("Receive the data length is %d",NumberOfBytes);
    int nOneFameLen=0;
    if (NumberOfBytes > 0)//数据大于0
    {
        if ((m_iDataLen + NumberOfBytes) > MAX_BUFFER_LENGTH)//超出缓冲区大小,丢弃
        {
            HPR_ZeroMemory(m_pDataBuff,MAX_BUFFER_LENGTH);
            m_iDataLen = 0;
            m_iOneFameLen=0;
            LOG_ERROR("DataBuff's length is more than MaxBuff!");
            return HPR_ERROR;
        }
        else
        {
            memmove(m_pDataBuff+m_iDataLen, m_stRecvBuf.gRecvBuff,NumberOfBytes);//将数据放入缓冲区
            m_iDataLen+=NumberOfBytes;
        }
        while (m_iDataLen>=HeaderLenth)//数据长度大于协议头长度
        {
            HPR_INT32 msgLen=0;
            HPR_INT32 msgtype = 0;
            HeaderPacket headPack;
            memmove(&headPack,m_pDataBuff,HeaderLenth);//将协议头放入结构体头部
            int msglen = headPack.lenth;//得到包数据长度
            LOG_INFO("The xml length is %d",msgLen);
            if(msgLen<0)
            {
                LOG_INFO("Parase the Data length is less then zero %d",msgLen);
                return HPR_ERROR;
            }
            m_iOneFameLen= HeaderLenth +msgLen;//得到协议头和包数据的长度
            LOG_INFO("One Frame length is %d",m_iOneFameLen);
            if (m_pDataBuff[0]!='H'||m_pDataBuff[1]!='K'||m_pDataBuff[2]!='P'||m_pDataBuff[3]!='&')//判断协议头
            {
                LOG_ERROR("协议头错误,data:%s", m_pDataBuff);
                //查找协议头
                int i = 0;
                for (i = 0; i < m_iDataLen&&i < MAX_BUFFER_LENGTH; i++)//如果前四个字节不是协议头,进入查找
                {
                    if (m_pDataBuff[i] == 'H')
                    {
                        if ((i+1)>=m_iDataLen)//长度只有1 不够
                        {
                            break;
                        }
                        if (m_pDataBuff[i+1]=='K')
                        {
                            if ((i+2)>=m_iDataLen)//长度只有2 不够
                            {
                                break;
                            }
                            if (m_pDataBuff[i+2]=='P')
                            {
                                if ((i + 3) >= m_iDataLen)//长度只有3 不够
                                {
                                    break;
                                }
                                if (m_pDataBuff[i + 3] == '&')
                                {
                                    break;//找到协议头,跳出循环
                                }
                            }
                        }
                    }
                }
                //将databuff向前移动i位
                memmove(m_pDataBuff, m_pDataBuff + i, m_iDataLen - i);//删除前面i个脏数据
                m_iDataLen = m_iDataLen - i;//重新计算缓冲区数据长度
                HPR_ZeroMemory(m_pDataBuff+ m_iDataLen,MAX_BUFFER_LENGTH- m_iDataLen);//将缓冲区后面的数据置零
                m_iOneFameLen=0;
                LOG_ERROR("Pro is wrong!\n");
            }
            else//头部是协议头,处理数据
            {
                if (m_iDataLen>=m_iOneFameLen)
                {
                    ParseRecvMessage(headPack.type,m_pDataBuff+ HeaderLenth,m_iOneFameLen);
                    memmove(m_pDataBuff,m_pDataBuff+m_iOneFameLen,m_iDataLen-m_iOneFameLen);
                    m_iDataLen-=m_iOneFameLen;
                    HPR_ZeroMemory(m_pDataBuff+m_iDataLen,MAX_BUFFER_LENGTH-m_iDataLen);
                }
                else
                {
                    LOG_INFO("The data is Less than oneFrame,keep recieve\n");
                    break;
                }
            }
        }    
    }
    return HPR_OK;
}
HPR_INT32 CCuItem::ParseData(HPR_ULONG NumberOfBytes)
{
    HPR_UINT16 iRetVal = HPR_ERROR;
    if( NumberOfBytes<0)
    {
        LOG_ERROR("ParseDataFromUtdu Point is NULL");
        return iRetVal;
    }
    LOG_INFO("Receive the data length is %d",NumberOfBytes);
    int nOneFameLen=0;
    if (NumberOfBytes > 0)//数据大于0
    {
        if ((m_iDataLen + NumberOfBytes) > MAX_BUFFER_LENGTH)//超出缓冲区大小,丢弃
        {
            HPR_ZeroMemory(m_pDataBuff,MAX_BUFFER_LENGTH);
            m_iDataLen = 0;
            m_iOneFameLen=0;
            LOG_ERROR("DataBuff's length is more than MaxBuff!");
            return HPR_ERROR;
        }
        else
        {
            memmove(m_pDataBuff+m_iDataLen, m_stRecvBuf.gRecvBuff,NumberOfBytes);//将数据放入缓冲区
            m_iDataLen+=NumberOfBytes;
        }
        while (m_iDataLen>=HeaderLenth)//数据长度大于协议头长度
        {
            HPR_INT32 msgLen=0;
            HPR_INT32 msgtype = 0;
            HeaderPacket headPack;
            memmove(&headPack,m_pDataBuff,HeaderLenth);//将协议头放入结构体头部
            int msglen = headPack.lenth;//得到包数据长度
            LOG_INFO("The xml length is %d",msgLen);
            if(msgLen<0)
            {
                LOG_INFO("Parase the Data length is less then zero %d",msgLen);
                return HPR_ERROR;
            }
            m_iOneFameLen= HeaderLenth +msgLen;//得到协议头和包数据的长度
            LOG_INFO("One Frame length is %d",m_iOneFameLen);
            if (m_pDataBuff[0]!='H'||m_pDataBuff[1]!='K'||m_pDataBuff[2]!='P'||m_pDataBuff[3]!='&')//判断协议头
            {
                LOG_ERROR("协议头错误,data:%s", m_pDataBuff);
                //查找协议头
                int i = 0;
                for (i = 0; i < m_iDataLen&&i < MAX_BUFFER_LENGTH; i++)//如果前四个字节不是协议头,进入查找
                {
                    if (m_pDataBuff[i] == 'H')
                    {
                        if ((i+1)>=m_iDataLen)//长度只有1 不够
                        {
                            break;
                        }
                        if (m_pDataBuff[i+1]=='K')
                        {
                            if ((i+2)>=m_iDataLen)//长度只有2 不够
                            {
                                break;
                            }
                            if (m_pDataBuff[i+2]=='P')
                            {
                                if ((i + 3) >= m_iDataLen)//长度只有3 不够
                                {
                                    break;
                                }
                                if (m_pDataBuff[i + 3] == '&')
                                {
                                    break;//找到协议头,跳出循环
                                }
                            }
                        }
                    }
                }
                //将databuff向前移动i位
                memmove(m_pDataBuff, m_pDataBuff + i, m_iDataLen - i);//删除前面i个脏数据
                m_iDataLen = m_iDataLen - i;//重新计算缓冲区数据长度
                HPR_ZeroMemory(m_pDataBuff+ m_iDataLen,MAX_BUFFER_LENGTH- m_iDataLen);//将缓冲区后面的数据置零
                m_iOneFameLen=0;
                LOG_ERROR("Pro is wrong!\n");
            }
            else//头部是协议头,处理数据
            {
                if (m_iDataLen>=m_iOneFameLen)
                {
                    ParseRecvMessage(headPack.type,m_pDataBuff+ HeaderLenth,m_iOneFameLen);
                    memmove(m_pDataBuff,m_pDataBuff+m_iOneFameLen,m_iDataLen-m_iOneFameLen);
                    m_iDataLen-=m_iOneFameLen;
                    HPR_ZeroMemory(m_pDataBuff+m_iDataLen,MAX_BUFFER_LENGTH-m_iDataLen);
                }
                else
                {
                    LOG_INFO("The data is Less than oneFrame,keep recieve\n");
                    break;
                }
            }
        }    
    }
    return HPR_OK;
}