QTcpSocket 通讯 ( 服务器、客户端、封包、解包 )

来源:互联网 发布:广告算法工程师招聘 编辑:程序博客网 时间:2024/06/12 13:03

转载请注明出处:http://blog.csdn.net/lthcth111/article/details/78175341

一、简介

简单实现 QTcpSocket  通讯,包含有服务器、客户端界面,和封包、解包过程,示例界面如下。

二、数据包结构

注:长度 = sizeof( 包类型 + 数据 + 包尾 )

三、部分代码展示

  • 封包
// 封包并发送void SocketClient::send(QByteArray data, QByteArray dataType){    QTcpSocket *socket = m_dataSocket;    if(socket == NULL || (socket !=  NULL &&       socket->state() !=  QTcpSocket::ConnectedState))    {        return;    }    QByteArray packet = dataType + data + NET_PACKET_END; //[包类型 + 数据 + 包尾]    //长度占8字节,前面补零,如"00065536"    int size = packet.size();    QByteArray length = QByteArray().setNum(size);    length = QByteArray(NET_PACKET_LTNGTH_BYTES, '0') + length;    length = length.right(NET_PACKET_LTNGTH_BYTES);    packet.insert(0, NET_PACKET_START + length);//插入 [包头 + 数据长度]    socket->write(packet);}

  • 解包
// 读取 socket 数据void SocketClient::OnReadyRead(){    QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());    if(socket == m_dataSocket )    {        m_dataPacket.data += socket->readAll();        // 循环解析包数据,m_dataPacket.data 中可能不只一包数据        bool isOk = false;        do{            isOk = parsePacket(socket, &m_dataPacket);        }while(isOk);    }    else    {        MY_LOG("socket connection abnormal");    }}// 解包bool SocketClient::parsePacket(QTcpSocket *socket, SocketPacket *packet){    int pIndexStart = packet->data.indexOf(NET_PACKET_START);    if(pIndexStart < 0)    {        return false;    }    packet->data = packet->data.mid(pIndexStart); //截取从包头index_start到末尾的数据    SocketPacket tmpPacket;    tmpPacket.data = packet->data;    tmpPacket.data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头    //解析包长度    if(tmpPacket.data.count() < NET_PACKET_LTNGTH_BYTES)    {        return false;    }    bool isOk;    tmpPacket.length = tmpPacket.data.mid(0, NET_PACKET_LTNGTH_BYTES).toLong(&isOk);    if(isOk == false)    {        packet->data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头        if(packet->data.indexOf(NET_PACKET_START) >= 0)        {            return true;//有可能出现粘包的情况,继续解析后面数据        }        else        {            return false;        }    }    //数据到达包长度    tmpPacket.data.remove(0, NET_PACKET_LTNGTH_BYTES);//删除数据长度    if(tmpPacket.length > tmpPacket.data.count())    {        return false;    }    //包尾是否匹配    tmpPacket.data.resize(tmpPacket.length);//删除多余数据    if(tmpPacket.data.endsWith(NET_PACKET_END) == false)    {        packet->data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头        if(packet->data.indexOf(NET_PACKET_START) >= 0)        {            return true;//有可能出现粘包的情况,继续解析后面数据        }        else        {            return false;        }    }    tmpPacket.data.resize(tmpPacket.length -                          QByteArray(NET_PACKET_END).count()); //删除包尾    //解析出数据类型    if(tmpPacket.data.count() < NET_PACKET_TYPE_BYTES)    {        return false;    }    QByteArray dataType = tmpPacket.data.left(NET_PACKET_TYPE_BYTES);    tmpPacket.dataType = dataType;    tmpPacket.data.remove(0, NET_PACKET_TYPE_BYTES);//删除数据类型    //发送数据包消息    if(socket == m_dataSocket)    {        emit dataPacketReady(tmpPacket);    }    //删除当前包数据    packet->data.remove(0,                        QByteArray(NET_PACKET_START).size()                        + NET_PACKET_LTNGTH_BYTES                        + tmpPacket.length);    return true;}

四、完整代码下载

CSDN 下载
客户端和服务器:http://download.csdn.net/download/lthcth111/10011256

码云下载
客户端:https://gitee.com/2649549484/TcpClientSimple
服务器:https://gitee.com/2649549484/TcpServerSimple

五、开发环境

Win7 + Qt 5.5.0

原创粉丝点击