QTcpSocket发送数据和自定义数据
来源:互联网 发布:军用望远镜软件下载 编辑:程序博客网 时间:2024/05/22 06:57
在网络应用中,有时候我们会遇到这样的问题,用TCP不断的接收和发送不同类型的数据,数据大小,格式都不相同,起初看了qt的例子,按照例子写的程序效果相当的不好,尤其是在连续发送大数据的时候,接收端根本无法判断数据是否完整了,也不知道什么时候取读取,经过各种折腾加上看qt源码,总结出了这个方法,发送的时候,要先发送这个数据序列化后的大小,然后发送这个数据本身,接收端,首先收到了要接收数据的大小,心里有数了,等到缓存区的数据大于或者等于要接收数据大小的时候,再过去取数据,就保证了数据的正确完整和及时。最开始的时候,用QByteArry发送数据,先发送了这个QByteArry的size,然后接着发送了这个QByteArry,结果发现了一个很悲剧的事情,一万个数据里面,有几百个数据不完整,找了半天原因才发现,QByteArry在序列化过程中,首先序列化了自身的size,然后才是自身,导致序列化后大小比之前的size大了4,同样QString也是一样,就用一个自定义的结构体来做例子说明,首先自定义结构体
源码链接http://pan.baidu.com/s/1kVAAgTp
class sendStruct{public: explicit sendStruct(int Type,QString Description,QByteArray ByteData=QByteArray(0)); int Type;//用于区分发送的不同内容的数据,对应不同的解析方法 QString Description;//发送内容的描述 QByteArray ByteData;//具体发送或者接受的内容,可以将所有基本类型int,char,vector,map等或者自定义的结构体通过 //QDataStream序列化到ByteData中,接收端同样的方法从QDataStream中解析出来原数据 sendStruct(){ Type=0; Description=""; ByteData=QByteArray(0);} int size() { int size=0; size=sizeof(int)+Description.size()*2+4+ByteData.size()+4; //序列化后QString大小为原有大小乘以2加4,QByteArry序列化后大小为原始大小加4,QString为Unicode编码每个字符占两个字节, //QString和QByteArry序列化过程中,首先序列化了本身大小的整形数据(qint32)到序列中,然后才是具体数据。 return size; } int size() const { int size=0; size=sizeof(int)+Description.size()*2+4+ByteData.size()+4; return size; } sendStruct &operator=(const sendStruct &other) { Type=other.Type; Description=other.Description; ByteData=QByteArray(other.ByteData); return *this; }#ifndef QT_NO_DATASTREAM friend QDataStream& operator <<(QDataStream& out,const sendStruct& senstruct) { out<<senstruct.Type <<senstruct.Description <<senstruct.ByteData; return out; } friend QDataStream& operator >>(QDataStream& in,sendStruct& senstruct) { in>>senstruct.Type >>senstruct.Description >>senstruct.ByteData; return in; }#endif};
定义TCP服务端和客户端
#ifndef TCPSERVERCONNECT_H#define TCPSERVERCONNECT_H#include <QObject>#include<QTcpServer>#include<QTcpSocket>class sendStruct;class TcpServerConnect : public QObject{ Q_OBJECTpublic: explicit TcpServerConnect(QObject *parent = nullptr);private: QTcpServer *m_server; QTcpSocket *m_tcpsocket; bool m_isGetPartData; int m_requestDataSize;public slots: void handleSendOutData(const sendStruct&); void handleGetRecieveData(); void handleNewConnection();};#endif // TCPSERVERCONNECT_H
#include "tcpserverconnect.h"TcpServerConnect::TcpServerConnect(QObject *parent) : QObject(parent) { m_tcpsocket=nullptr; m_isGetPartData=false; m_requestDataSize=0; m_server=new QTcpServer(this); connect(m_server,&QTcpServer::newConnection,this,&TcpServerConnect::handleNewConnection); m_server->listen(QHostAddress::Any,6868); }void TcpServerConnect::handleSendOutData(const sendStruct &data) { if((!m_tcpsocket)||m_tcpsocket->state()!=QAbstractSocket::ConnectedState) return; QDataStream out(m_tcpsocket); out<<data.size()<<data;//先发送了数据大小,在发送数据 m_tcpsocket->flush(); /*把需要发送的数据封装在结构体里面发送*/ }void TcpServerConnect::handleGetRecieveData() { if((!m_tcpsocket)||m_tcpsocket->state()!=QAbstractSocket::ConnectedState) return; if(m_isGetPartData==false){ if(m_tcpsocket->bytesAvailable()<sizeof(int))//先要得到数据的大小 return; else { QDataStream in(m_tcpsocket); in>>m_requestDataSize;//数据大小写入这个变量中 m_isGetPartData=true;//只获得了数据的大小,数据内容还未获得 } } if(m_isGetPartData==true){ if(m_tcpsocket->bytesAvailable()<m_requestDataSize)//判断是否数据接收完整了,不完整就返回等待下一次判断 return; else { QDataStream in(m_tcpsocket); sendStruct receiveData; in>>receiveData;//接收到了发送端的数据 m_requestDataSize=0;//清空大小 m_isGetPartData=false;//清空标志 /* 数据接收成功,放置在receiveData中,可以做其他处理 doSomething(receiveData); */ qDebug()<<"receiveData type"<<receiveData.Type; qDebug()<<"receiveData Description"<<receiveData.Description; qDebug()<<"receiveData ByteData"<<receiveData.ByteData; if(m_tcpsocket->bytesAvailable())//如果缓存区还存在数据,继续执行 handleGetRecieveData(); } } }void TcpServerConnect::handleNewConnection() { QTcpServer *server=static_cast<QTcpServer*>(sender()); m_tcpsocket=server->nextPendingConnection(); if(m_tcpsocket) connect(m_tcpsocket,&QTcpSocket::readyRead,this,&TcpServerConnect::handleGetRecieveData); sendStruct sendImageData; sendImageData.Type=0; sendImageData.Description=QString("this is image"); QImage image(QSize(640,480),QImage::Format_RGB888); image.fill(Qt::gray); QBuffer buffur(sendImageData.ByteData); buffur.open(QIODevice::ReadWrite); image.save(&buffur,"JPG"); handleSendOutData(sendImageData); sendStruct sendPointData; sendPointData.Type=1; sendPointData.Description="this is point"; QDataStream pointStream(&sendPointData.ByteData,QIODevice::WriteOnly); pointStream<<QPoint(100,100); handleSendOutData(sendPointData); }
#ifndef TCPCLIENTCONNECT_H#define TCPCLIENTCONNECT_H#include <QObject>#include<QTcpSocket>class sendStruct;class TcpClientConnect : public QObject{ Q_OBJECTpublic: explicit TcpClientConnect(QObject *parent = nullptr); QTcpSocket *m_tcpsocket; bool m_isGetPartData; int m_requestDataSize;public slots: void handleSendOutData(const sendStruct&); void handleGetRecieveData(); void handleSocketConnected();};#endif // TCPCLIENTCONNECT_H
#include "tcpclientconnect.h"TcpClientConnect::TcpClientConnect(QObject *parent) : QObject(parent) { m_tcpsocket=new QTcpSocket(this); m_isGetPartData=false; m_requestDataSize=0; connect(m_tcpsocket,&QTcpSocket::readyRead,this,&TcpClientConnect::handleGetRecieveData); connect(m_tcpsocket,&QTcpSocket::disconnected,this,&TcpClientConnect::handleSocketConnected); m_tcpsocket->connectToHost(QHostAddress("192.168.0.45"),6868); if(m_tcpsocket->waitForConnected(3000)==false){ qDebug()<<"connect error:"<<m_tcpsocket->errorString(); } }void TcpClientConnect::handleSendOutData(const sendStruct &data) { if((!m_tcpsocket)||m_tcpsocket->state()!=QAbstractSocket::ConnectedState) return; QDataStream out(m_tcpsocket); out<<data.size()<<data;//先发送数据大小,在发送数据本身 m_tcpsocket->flush(); /*把需要发送的数据封装在结构体里面发送*/ }void TcpClientConnect::handleGetRecieveData() { if((!m_tcpsocket)||m_tcpsocket->state()!=QAbstractSocket::ConnectedState) return; if(m_isGetPartData==false){ if(m_tcpsocket->bytesAvailable()<sizeof(int))//先接收数据的大小 return; else { QDataStream in(m_tcpsocket); in>>m_requestDataSize;//数据大小写入变量 m_isGetPartData=true;//设置标志,只接收到了数据大小,没接收到数据全部 } } if(m_isGetPartData==true){ if(m_tcpsocket->bytesAvailable()<m_requestDataSize)//判断是否接收到了完整的数据 return; else { QDataStream in(m_tcpsocket); sendStruct receiveData; in>>receiveData;//接收到了数据 m_requestDataSize=0;//清空大小 m_isGetPartData=false;//清空标志 /* 数据接收成功,放置在receiveData中,可以做其他处理 doSomething(receiveData); */ qDebug()<<"receiveData type"<<receiveData.Type; qDebug()<<"receiveData Description"<<receiveData.Description; qDebug()<<"receiveData ByteData"<<receiveData.ByteData; if(m_tcpsocket->bytesAvailable())//如果缓存区还存在数据,递归执行 handleGetRecieveData(); } } }void TcpClientConnect::handleSocketConnected() { sendStruct sendImageData; sendImageData.Type=0; sendImageData.Description=QString("this is image"); QImage image(QSize(640,480),QImage::Format_RGB888); image.fill(Qt::gray); QBuffer buffur(sendImageData.ByteData); buffur.open(QIODevice::ReadWrite); image.save(&buffur,"JPG"); handleSendOutData(sendImageData); sendStruct sendPointData; sendPointData.Type=1; sendPointData.Description="this is point"; QDataStream pointStream(&sendPointData.ByteData,QIODevice::WriteOnly); pointStream<<QPoint(100,100); handleSendOutData(sendPointData); }
阅读全文
0 0
- QTcpSocket发送数据和自定义数据
- QTcpSocket 发送数据心得
- QTcpSocket的连续发送数据和连续接收数据
- QTcpSocket的连续发送数据和连续接收数据
- QT QTcpSocket发送数据问题
- QTcpSocket 发送和接收数据的几种方法
- QTcpSocket 发送数据的几种方法
- QTcpSocket 发送数据的几种方法
- 关于QT中用QTcpserver 和QTcpsocket接收和发送数据的一个规则理解
- Qt QtcpSocket 发送文件(包括数据块总大小)
- 使用QTcpSocket接收数据
- Qt中的QTcpSocket类的write()方法不能发送数据的解决方法
- Qt中的QTcpSocket类的write()方法不能发送数据的解决方法
- Filter发送自定义数据详解
- 发送和读取数据
- 数据发送和接收
- 发送和接受数据
- qt4 tcp QTcpSocket QTcpServer 传输数据
- 回调函数
- 一键离线地图发布(工具软件下载) 使用教程
- Physics-based Animation 相关
- Class PLBuildVersion is implemented in both frameworks
- NOIP2015提高组 神奇的幻方
- QTcpSocket发送数据和自定义数据
- jstree中文github文档
- SHELL脚本编程进阶(二)
- vue项目nav导航栏的实现
- 微信小程序SetData的问题
- UOJ264 NOIP2016 day2 T2 蚯蚓(队列)
- 国内注册Gmail
- 摄像相机标定到底是啥?标定完成得到的参数有什么用?
- required 'Android.support.v4.app.Fragment' found 'android.app.Fragment.'错误解决