网盘系统Qt5实现- 通讯协议设计

一、弹性结构体

二、通讯协议设计

设计数据协议单元的数据结构

#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>

typedef unsigned int uint;

struct PDU
{
    uint uiPDULen;   //总的协议数据单元大小
    uint uiMsgType;  //消息类型
    char caData[64];  //消息数据
    uint uiMsgLen;   //实际消息的长度
    int caMsg[];  //实际消息
};

PDU* mkPDU(uint uiMsgLen);  //创建协议数据单元

 通过动态申请实际消息的大小,通过访问结构体最后的数组的地址来访问消息。

#include"protocol.h"


PDU *mkPDU(uint uiMsgLen)
{
    uint uiPDULen = sizeof(PDU) + uiMsgLen;
    PDU* pdu = (PDU*)malloc(uiPDULen);
    if(NULL == pdu)
    {
        exit(EXIT_FAILURE);
    }
    memset(pdu,0,uiPDULen); // 将pdu所指向的内存空间清0
    pdu->uiPDULen = uiPDULen;
    pdu->uiMsgLen = uiMsgLen;
    return pdu;
}

三、数据收发测试

测试数据的接收

void TcpClient::on_send_btn_clicked()
{
    QString strMsg = ui->lineEdit->text();
    if(!strMsg.isEmpty()){
        PDU* pdu = mkPUD(strMsg.size());
        pdu->uiMsgType = 8888;
        memecpy(pdu->caData,strMsg.toStdString().c_str(),strMsg.size());
        m_tcpSocket.write((char*)pdu , pdu->uiPDULen);
        free(pdu);
        pdu = NULL;
    }
    else{
        QMessageBox::warning(this,"信息发送","发送数据不能为空!");
    }
}

通过测试发现通过拷贝后的数据如果是中文,则会导致出现乱码,

解决方法如下:

使用memcpy将QString类型的消息内容复制到了PDU结构体中的caData成员。但是,memcpy仅适用于二进制数据的复制,对于包含字符串的QString,可能需要考虑字符串编码的问题。

由于输出的数据可能包含中文字符,建议使用QString的toUtf8函数来获取UTF-8编码的字节数

组,然后使用memcpy进行复制。

void TcpClient::on_send_btn_clicked()
{
    QString strMsg = ui->lineEdit->text();
    if (!strMsg.isEmpty()) {
        QByteArray utf8Data = strMsg.toUtf8();
        PDU* pdu = mkPDU(utf8Data.size());
        pdu->uiMsgType = 8888;
        memcpy(pdu->caData, utf8Data.constData(), utf8Data.size());
        m_tcpSocket.write((char*)pdu, pdu->uiPDULen);
        qDebug() << "send msg data:" << pdu->caData;
        free(pdu);
        pdu = NULL;
    } else {
        QMessageBox::warning(this, "信息发送", "发送数据不能为空!");
    }
    qDebug() << "send msg:" << strMsg;

}

通过测试,客户端这边显示正常 

 

再对服务器进行测试

这里单独设计了一个类mytcpsocket,专门用于接收消息

#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket>

class MyTcpSocket : public QTcpSocket
{
    Q_OBJECT

public:
    explicit MyTcpSocket(QObject *parent = nullptr);

public slots:
    void recvMsg();

};

#endif // MYTCPSOCKET_H
#include "mytcpsocket.h"
#include<QDebug>
#include"protocol.h"

MyTcpSocket::MyTcpSocket(QObject *parent)
    : QTcpSocket{parent}
{
    connect(this,&MyTcpSocket::readyRead
            ,this,&MyTcpSocket::recvMsg);
}

void MyTcpSocket::recvMsg()
{
    qDebug()<<this->bytesAvailable();
    uint uiPDULen = 0;
    this->read((char*)&uiPDULen,sizeof(uint));
    uint uiMsgLen = uiPDULen - sizeof(PDU);
    PDU* pdu = mkPDU(uiMsgLen);
    this->read((char*)pdu+sizeof(uint),uiPDULen-sizeof(uint));
    qDebug()<<pdu->uiMsgType<<(char*)pdu->caData;
}

每次接收消息后,都会有一个单独的tcpsocket类来管理,并添加到列表中

void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug()<<"new client connected!";
    MyTcpSocket* pTcpSocket = new MyTcpSocket;
    pTcpSocket->setSocketDescriptor(socketDescriptor);
    m_tcpSocketList.append(pTcpSocket);
}

启动客户端向服务器发送消息进行测试,测试结果正常 

至此通讯协议设计完成,客户端和服务器已经可以正常通信了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值