Qt TCP之自定义通信协议
2017-07-01 17:10
399 查看
在已经实现socket通信的前提下,设计了如下的通信格式:
假设cmd定义如下:
一些变量说明:
发送QString字符串
发送QFile文件
发送Struct结构体文件
接收QString、QFile和Struct结构体文件
假设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(); 4000 //这边确实需要利用长度做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; } }
相关文章推荐
- QT下TCP协议通信的Client端
- 一个简单的TCP自定义通信协议
- 一种RS-485总线自定义通信协议及其应用(转)
- DOS下加载TCP协议通信介绍
- 一个简单的自定义通信协议(socket)
- 自定义应用层通信协议(1)
- 使用SuperSocket实现TLV自定义协议网络通信的Demo
- 嵌入式 TCP/IP 协议单片机技术在网络通信中的应用
- 自定义应用层通信协议
- 使用Lua脚本为wireshark编写自定义通信协议解析器插件
- 一个简单的自定义通信协议(socket)
- 自定义应用层通信协议
- 基于qt的一个tcp通信小程序
- TCP/IP 通信协议 应用浅析
- 证书的应用之一 —— TCP&SSL通信实例及协议分析(上)
- 无线网络中传输层通信协议分析与比较(TCP与UDP)
- 检测到通信错误。正在使用的通信协议:"TCP/IP"。正在使用的通信API:"SOCKETS"。检测到错误的位置:""。检测到错误的通信函数:"gethostbyname"。协议特定的错误代码:"*"、"11004"、"*"。 SQLST
- QT中TCP/UDP通信数据的组织
- 证书的应用之一 —— TCP&SSL通信实例及协议分析(下)
- 一种自定义网络通信协议