Qt TCP之自定义通信协议
来源:互联网 发布:在哪里买正版windows 编辑:程序博客网 时间:2024/05/22 01:34
在已经实现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; }}
阅读全文
0 0
- Qt TCP之自定义通信协议
- JAVA Socket通信中自定义TCP通信协议
- 一个简单的TCP自定义通信协议
- tcp通信协议
- 通信协议之Http、TCP、UDP详解
- NanShan即时通讯之自定义通信协议设计基础
- 自定义通信协议设计之TLV编码应用
- 自定义通信协议
- 自定义通信协议
- 网络编程学习之——TCP通信协议
- Python进阶之UDP和TCP通信协议实例
- qt之tcp
- window通信协议TCP/IP
- 通信协议HTTP、TCP、UDP
- 通信协议-HTTP/TCP/UDP
- 通信协议:HTTP、TCP、UDP
- 通信协议:HTTP、TCP、UDP
- 通信协议:HTTP、TCP、UDP
- Linux(ubuntu16.04)下安装nodejs及配置环境变量
- 《瓦尔登湖》序六
- 快速排序
- centos 下查看本机公网IP
- python2与python3区别(一)
- Qt TCP之自定义通信协议
- commons fileupload的DiskFileItemFactory
- Angular学习笔记
- JSP中的Script标签
- 模拟登录Django csrf验证 及 django_cas_server 模块验证
- MathWorks机器学习简介-1
- 整数排序II
- PS技巧三------五彩斑斓的黑色(滤镜---镜头光晕和波浪|||||混合选项---柔光)
- JDK环境变量配置