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

转载请注明出处: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/TcpServerSimple

五、开发环境

Win7 + Qt 5.5.0

Qt库中,如果你想要使用`QTcpSocket`类从客户端连接到服务器,并指定特定的客户端端口,你可以按照以下步骤操作: 1. 首先,创建一个`QTcpSocket`对象实例: ```cpp QTcpSocket *clientSocket = new QTcpSocket(this); ``` 这里,`this`通常是指向包含这个socket对象的QMainWindow或其他QObject。 2. 连接前确保网络套接字已初始化并设置正确的主机名和端口号: ```cpp if (!clientSocket->isValid()) { qDebug() << "Socket not initialized."; return; // 处理错误 } QString hostName("your_server_ip"); quint16 port(8080); // 或者你想使用的任意端口号 connect(clientSocket, &QTcpSocket::connected, clientSocket, &QTcpSocket::write); connect(clientSocket, &QTcpSocket::disconnected, this, &YourClass::onDisconnected); clientSocket->setHost(hostName); clientSocket->setPort(port); ``` 注意替换`your_server_ip`为实际的服务器IP地址。 3. 确保连接成功后开始通信: ```cpp if (clientSocket->connectToHost(hostName, port)) { qDebug() << "Connected to server at " << hostName << ":" << port; QByteArray dataToSend("Your message here"); // 要发送的数据 clientSocket->write(dataToSend); } else { qWarning() << "Failed to connect to the server"; } ``` 4. 当连接断开时,可以处理相关的事件: ```cpp void YourClass::onDisconnected() { qDebug() << "Connection to server lost."; delete clientSocket; } ``` 记得处理可能出现的异常和错误情况,例如超时、连接失败等。同时,在实际应用中,可能还需要添加适当的错误重试机制。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值