QT tcp通信之自定义通信协议_小米的修行之路的博客-程序员秘密

技术标签: QT  

转载自:https://blog.csdn.net/omg_orange/article/details/74075104,以下通信协议为转载,本人没有亲自测试正确否。

在已经实现socket通信的前提下,设计了如下的通信格式:

这里写图片描述

假设cmd定义如下:

#ifndef CMD_H
#define CMD_H

//服务器------->客户端
#define     Connet_Success         0x0F00   //连接成功应答包
#define     Login_answer           0x0F01   //登陆结果(也是QString 的一种)
#define     QString_send           0x0F02   //发送字符串
#define     QFile_send             0x0F03   //发送文件
#define     Struct_send            0x0F03   //发送结构体

//客户端------->服务器
#define     Login                  0x0D00   //客户端登陆

#endif // CMD_H

一些变量说明:

    qint64 totalBytes;      //一个数据包MSG部分的完整大小
    qint64 recvdBytes;      //已经收到的字节数
    qint64 serverCmd;       //接受数据包的类型
    QByteArray inBlock;     //接受缓冲
    QByteArray m_buffer;    //缓存上一次或多次的未处理的数据
    QFile *localFile;
    QSqlDatabase db;
    QMutex mutex;
  • 发送QString字符串
void mySocket::sendMSG(QString msg, qint64 cmd)
{
    if(!isValid()) //确保连接仍然有效
    {
        qDebug()<<"losing connect.......";
        return;
    }
    /********************构造数据包************************/
    qint64 totalBytes = 0;
    QByteArray block; //用于暂存我们要发送的数据
    QDataStream output(&block,QIODevice::WriteOnly);//使用数据流写入数据
    output.setVersion(QDataStream::Qt_5_2);
    totalBytes = msg.toUtf8().size();

    //  totalBytes+cmd  构成了包头 长度为2*qint64 也就是头文件中定义的MINSIZE
    output<<qint64(totalBytes)<<qint64(cmd); //将命令内容的长度、命令类型写入到数据流中去 cmdw为QString_send类型
    totalBytes += block.size();//加上上一行内容的长度
    output.device()->seek(0);//回到数据流的开始位置
    output<<totalBytes; //所有内容(msg+cmd+qint64)的长度
    write(block);
    block.resize(0);//清空
    for(int i=0;i<10000;i++); //延时

    block = msg.toUtf8();
    write(block);//发送命令内容
    block.resize(0);
}
  • 发送QFile文件
void mySocket::sendQFile(QString path)
{
   QFile localFile(path);
   if(!localFile.open(QFile::ReadOnly))
       return;
   qDebug()<<"open data file success";

   qint64 totalBytes = 0;
   QByteArray outBlock;
   outBlock.resize(0);
   QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
   sendOut.setVersion(QDataStream::Qt_5_2);
   totalBytes = localFile.size();

   sendOut<<qint64(totalBytes)<<qint64(QFile_send);
   totalBytes += outBlock.size();
   sendOut.device()->seek(0);
   sendOut<<totalBytes;
   write(outBlock);
   outBlock.resize(0);

   outBlock = localFile.readAll();
   write(outBlock);
   outBlock.resize(0);
   localFile.close();
}
  • 发送Struct结构体文件
void mySocket::sendStructData()
{
    if(!isValid())
        return;
    //构造数据包
    qint64 totalBytes = 2*sizeof(qint64) + sizeof(stu_stateData);//stu_stateData是
    QByteArray outBlock;
    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_2);
    outBlock.resize(totalBytes);
    //向缓冲区写入文件头
    sendOut<<totalBytes<<qint64(Struct_send);  
    //向缓冲区写入文件数据
    mutex.lock();
    memcpy(outBlock.data() + 2*sizeof(qint64),&stateData,sizeof(stu_stateData));
    mutex.unlock();
    write(outBlock);
    outBlock.resize(0);
}
  • 接收QString、QFile和Struct结构体文件
void mySocket::readMsg()
{
//如果不存在数据,就直接结束
    if(bytesAvailable() <= 0)
    {
        return;
    }

    //从缓存区中去除数据,但是不确定取出来的字节数
    QByteArray  buffer;
    buffer = readAll();
    m_buffer.append(buffer);
    unsigned int totalLen = m_buffer.size();
    //这边确实需要利用长度做while循环,因为有可能一下子读取到两条以上的完整记录,就需要进行循环处理了;
    //超过一条完整小于第二条完整记录时,如果已经达到包头长度就先把包头保存下来,整个过程循环往复
    while(totalLen)
    {
        //与QDataStream绑定,方便操作
        QDataStream  packet(m_buffer);
        packet.setVersion(QDataStream::Qt_5_2);
        //不够包头长度的不处理,结束while循环
        if(totalLen < MINSIZE)
            break;
        //将包头读入了进来按照定义的协议 先读命令长度,再读命令的类型
        packet>>totalBytes>>serverCmd; 
        //缓存中的内容长度没有达到命令的长度,那就先结束,等足够了再来解析
        if(totalLen<totalBytes)
            break;

        //足够长了就开始解析
        QDir dir(sysFilePath);      //系统文件目录
        if(!dir.exists())
            dir.mkdir(sysFilePath);

        switch(serverCmd)
        {
        case QString_send :    //接收QString
        {
            qDebug()<<"开始接收字符串...";
            QByteArray datas = m_buffer.mid(MINSIZE,totalBytes-MINSIZE);
            QString strInfo;//数据包中的message
            strInfo.prepend(datas);
            qDebug()<<strInfo;//输出接收到的QString
            break;
        }
        case QFile_send :    //接收文件
         {
            qDebug()<<"收到文件";
            qDebug()<<"文件大小为:"<<totalBytes;
            tmpfileName = sysFilePath+"file/something.txt"; //也可以是其他文件类型 如.db
            localFile = new QFile(tmpfileName);//真正的文件路径
            if(!localFile->open(QIODevice::WriteOnly)) //写的方式打开该文件
            {
                qDebug()<<tr("无法打开文件%1:\n%2.").arg(tmpfileName).arg(localFile->errorString());
                return;
            }
            localFile->resize(0);//清空文件         
            QByteArray datas = m_buffer.mid(MINSIZE,totalBytes-MINSIZE);
            localFile->write(datas);
            localFile->close();
            break;
          }
        case  Struct_send:
         {
            QByteArray realStateData = inBlock.mid(MINSIZE,totalBytes-MINSIZE);
            motionMutex.lock();
            memcpy(&motionData,realStateData.data(),sizeof(stu_stateData));   //motionData是一个stu_stateData结构体变量
            motionMutex.unlock();
            break;
         }
        }
        //缓存多余的数据
     buffer = m_buffer.right(totalLen - totalBytes); //截取下一个数据包的数据,留作下次读取
    totalLen = buffer.size();
    //更新多余的数据
    m_buffer = buffer;
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012372584/article/details/82781668

智能推荐

C++ 函数模板&类模板详解_函数模板归属于哪个类_Bird鸟人的博客-程序员秘密

在 C++ 中,模板分为函数模板和类模板两种。函数模板是用于生成函数的,类模板则是用于生成类的。函数模板&amp;amp;模板函数     类模板&amp;amp;模板类  必须区分概念函数模板是模板,模板函数时具体的函数类模板是模板,模板类时具体的类由函数模板实例化而得到的函数称为模板函数由类模板实例化得到的类叫模板类 一.函数模板函数模板的基本写法为:template &amp;lt;typ...

docker中mongo容器导出数据(按时间段) mongoexport_荔枝hu的博客-程序员秘密

文章目录背景简介开发背景条件操作符介绍单个组合时间操作Date()new Date()ISODate()mongoexport 简介按时间段导出mongoexport 在容器内生成csvdocker cp将容器内csv复制到主机上遇到的问题query无法识别 $gtquery无法识别 ISODate背景简介开发背景开发环境:docker中容器名:mongo(版本:mongo:4.2.3)mongo中相关配置:数据库(database):audit表(或集合collection):t_

绝缘监测产品在船舶岸电的应用_接入岸电时绝缘监测仪还能测吗?_syt910的博客-程序员秘密

苏月婷江苏安科瑞电气制造有限公司摘 要:随着船舶大型化,电力系统容量增大,对船舶电网安全性要求也越来越高,绝缘在线监测已经逐步成为现代船舶电网自动监测不可缺少的一部分。船舶相当一部分时间是停靠在码头,有码头岸电箱供电。除了日常生活用电外,船舶上过的许多电气设备在停泊时仍然需要工作。停泊时对船舶电网绝缘状态进行在线监测是非常重要的,它既可以避免一些事故的发生,也减少了船员检查电网绝缘的工作量。关键词:船舶电气;船舶电网;岸电;安全性;绝缘监测;故障定位0 行业背景 船舶相当一部分时间.

抖音视频评论采集_考古学家lx(李玺)的博客-程序员秘密

总结一下现在采集抖音评论的方法,根据不同的业务可以选择不同的采集方式。文章目录1、自动化工具采集2、第三方平台采集3、APP评论采集4、网页版评论采集专栏分享1、自动化工具采集如果是自己采集评论做一些样本,数据量要求不是很高。可以使用fiddler、charles、或者mitmproxy 这些拦截工具,配合按键精灵或者自动化脚本讲加载的评论数据保存到本地。 (最好使用安卓系统为5的模拟器,防止ssl-pining)《Charles保存抖音数据》《Fiddler保存抖音数据》mitm拦截示例:f

Invoke 和 BeginInvoke 的区别_weixin_33804990的博客-程序员秘密

在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate。 一、为什么Control类提供了Invoke和BeginInvoke机制?关于这个问题的最主要的原因已经是dotnet程序员众所周知的,我在此费点笔墨再次记录到自己的日志,以便日后提醒一下自己。1、windows程序消息机制Windows GUI程序是基于消息机制的,有个主线程维护着一个消息泵。...

什么是Portlet ?_javachannel的博客-程序员秘密

什么是Portlet ?作者:Sunil Patil译者:observer版权声明:任何获得Matrix授权的网站,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明作者:Sunil Patil;observer原文地址:http://www.onjava.com/pub/a/onjava/2005/10/19/challenging-java-dominance.html中文地址:htt

随便推点

在CSDN安家_delsen的博客-程序员秘密

<br />管理员告诉我要写一篇博客才能开通,so,我随便写一篇

java实现聊天室界面javafx_java 聊天室WeChat_weixin_39959569的博客-程序员秘密

功能和特性基于socket实现的c/s架构的的通信服务器和客户心跳连接gson实现的消息通信机制注册及登录支持私聊和群聊。动态更新用户列表以及用户消息提示支持emoji表情,以及emoji表情选择器服务器端数据库用户记录实现文件传输文件记录功能展示loginchatroom表情包数据库整体架构使用了比较简单的worker-master架构。由masterserve进行事件的分发由workserve...

Linux系统中,多个CUDA版本切换_linux切换cuda版本_TEn%的博客-程序员秘密

1. 设置环境变量sudo vi ~/.bashrc进入bashrc文件后,在文件末尾添加以下代码,用来设置cuda的环境变量:export CUDA_HOME=$CUDA_HOME:/usr/local/cuda export PATH=$PATH:/usr/local/cudaexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64设置完毕后如下图所示:**注意:**如果大家按照下图设置的话,这是硬链接,无法设置软连接

ARCPY批量CSV转换成SHP,批量近邻匹配_arcpy csv转shp_初见与告别的博客-程序员秘密

Arcpy批量CSV转SHP文件以及批量近邻匹配,比导入Arcgis快

Multicarrier Interpretation of OTFS(OTFS的多载波解释)(7)_三省少年的博客-程序员秘密

content1.overview(概述)2.Details(细节)2.1Introduction of delay-doppler grid and time-frequency grid(时延多普勒网格和时间频率网格的介绍)2.2Fourier relation between the two grids(两个网格之间的傅里叶关系)2.3About symplectic exponential function(关于辛指数函数)3.Conclusion1.overview(概述)In this se

推荐文章

热门文章

相关标签