【笔记】解决TCP长连接中的沾包问题

TCP自定义报头结构体:

/*!
 * @brief tcp自定义包头
 */
struct TcpPacketHead{
    TcpPacketHead():flag(0X52474B4A)
    {

    }
    uint   flag;          /*!< 0X52474B4A */
    uint   index;         /*!< 帧计数 */
    uint   msgType;       /*!< 消息类型 */
    ushort length;        /*!< 数据长度 */
    ushort totalLenth;    /*!< 数据总长度 */
    ushort recvId;        /*!< 发送方id */
    ushort taskId;        /*!< 任务id */

};

需要定义的变量:

/********** tcp接收报文相关 **************/
    qint64 bytesReceived;  /** tcp当前报文已经接收的大小 */
    qint64 recv_totalBytes; /** tcp当前报文需要收到的总大小 */
    Datastruct::TcpPacketHead *now_tcpHead;/** 指向当前的要接收的tcp报文头 */
    QByteArray now_recv_array;/** 用来存放当前接收到的tcp报文,接收完后才开始解析,长度超出则是下一个报文,取走当前报文后保留 */

变量初始化:(在创建连接的函数中,如connect_server())

	bytesReceived = 0;  /** 初始化tcp当前报文已经接收的大小为0 */
    recv_totalBytes = 0; /** 初始化tcp当前报文需要收到的总大小为0 */
    now_tcpHead = NULL;/** 初始化在接收的当前tcp报头为空 */
    now_recv_array.clear();/** 清空当前收到的报文 */

更新tcp报文的处理槽

/**
 * @brief TcpClient::slotdisconnected
 * 请求断开连接后,需要对界面进行的操作
 */
void TcpClient::slotdisconnected()
{
    stateTimer->stop();
    qDebug()<bytesAvailable();
    QByteArray recv_array = tcpsocket->readAll();
    qDebug()<sizeof(Datastruct::TcpPacketHead))&&(now_tcpHead == NULL))/** 如果大于报文的大小了,则可以先解析出来一个头,然后判断够不够 */
    {
        now_tcpHead = (Datastruct::TcpPacketHead *)now_recv_array.data();
        recv_totalBytes = now_tcpHead->totalLenth;
        if((now_tcpHead->flag)== 0X52474B4A)
        {/** 看报文对不对 */
            if(bytesReceived  recv_totalBytes)/** 说明有下一次的报文在里面 */
            {   qDebug()<<"have next package++++++++";/** 出现沾包了,正在解决 */
                QByteArray myarrary = now_recv_array.left(recv_totalBytes);/** 本次报文  */
                unwarp(myarrary);

                bytesReceived = bytesReceived - recv_totalBytes ;/** 下一次报文已经收到的长度 */
                recv_totalBytes = 0;/** 收到的总共的置0,不过下一次解析报头的时候其实会直接覆盖 */
                now_tcpHead = NULL;/** 当前报头重新置空 */
                now_recv_array = now_recv_array.right(bytesReceived);/** 实际收到的下一次报文 */
                slot_updateTcpPackage();/** 手动调用一下,检查是不是这一次剩下的直接够了第二包,避免需要下一次报文才触发检查 */

                return;
            }
        }
        else{/** 如果发现有解析不出来的报文了,直接丢弃然后清空当前收到状态,即重置到刚连接的状态 */
            qDebug()<<"error TCPhead!!!!!!!";
            bytesReceived = 0;/** 重置接收到的数据字节数  */
            recv_totalBytes = 0;/** 下一次其实会覆盖,重置不重置都可以 */
            now_recv_array.clear();/** 清空当前接收到的 */
            now_tcpHead = NULL;
            return;

        }

    }


}

注意前面需要绑定一下信号槽:

connect(tcpsocket, &QTcpSocket::readyRead, this, &TcpClient::slot_updateTcpPackage);

与tcpsocket对象的readyRead信号绑定,可以和前面的变量初始化一起放到创建连接的函数里,如connect_server()

你可能感兴趣的:(【笔记】解决TCP长连接中的沾包问题)