如何通过QTcpSocket发送自定义类vector?服务端崩溃求助
问题:QTcpSocket传输自定义类的std::vector时服务端崩溃
尝试通过QTcpSocket从客户端向服务端发送存储自定义data类的std::vector,数据已完成传输,但服务端尝试将数据输出到控制台时发生崩溃。而发送存储int等基础类型的vector时,一切运行正常。
客户端代码
#include <QCoreApplication> #include <QTcpSocket> #include <QDataStream> #include "data.h" //client int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); std::vector< data > wektor; data asd; asd.setName("asd"); wektor.push_back(asd); wektor.push_back(asd); for (data w : wektor){ qDebug()<<w.getName(); } quint16 rozmiarSampla = sizeof( wektor[0] ); quint16 ileSampli = wektor.size(); QTcpSocket socket; socket.connectToHost("127.0.0.1",9999); if( !socket.waitForConnected() ) return 1; QDataStream stream(&socket); QString typ("Paczka z buforem"); stream << typ << rozmiarSampla << ileSampli; stream.writeRawData( reinterpret_cast<const char*>( wektor.data() ) , rozmiarSampla * ileSampli ); socket.flush(); socket.waitForBytesWritten(); return 0; }
服务端代码
#include <QCoreApplication> #include <QTcpServer> #include <QTcpSocket> #include <QDataStream> #include <QScopedPointer> #include "data.h" #include <iostream> #include <string.h> //serwer int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); std::vector< data > wektor; QString typ; quint16 rozmiarSampla; quint16 ileSampli; QTcpServer serwer; serwer.listen(QHostAddress::AnyIPv4,9999); if( !serwer.waitForNewConnection(30000) ) return 1; QScopedPointer<QTcpSocket> socket{ serwer.nextPendingConnection() }; if(! socket->waitForReadyRead() ) return 1; QDataStream stream(socket.data()); stream >> typ >> rozmiarSampla >> ileSampli; if( rozmiarSampla == sizeof( wektor[0] ) ) { wektor.resize(ileSampli); stream.readRawData( reinterpret_cast<char*>( wektor.data() ) , rozmiarSampla * ileSampli ); } else { stream.skipRawData(rozmiarSampla * ileSampli); } qDebug() << "Typ: " << typ; qDebug() << "RozmiarSampla: " << rozmiarSampla; qDebug() << "IleSampli: " << ileSampli; qDebug()<<wektor.size(); qDebug()<< wektor[0].getName(); return a.exec(); }
DATA.H
#ifndef DATA_H #define DATA_H #include <QtCore> class data { public: data(); void setName(QString name); QString getName(); private: QString Name; }; #endif // DATA_H
DATA.CPP
#include "data.h" #include <QtCore> data::data() { this->Name = "null"; } void data::setName(QString name) { this->Name = name; } QString data::getName() { return this->Name; }
崩溃原因分析
- 你直接使用
writeRawData和readRawData传输data对象的二进制内存,这种方式仅适用于纯基础类型(如int、char)的对象。 data类中的QString Name是Qt的动态字符串类型,它内部并非直接存储字符串内容,而是包含一个指向堆内存的指针。你传输的只是这个指针的数值,而非字符串的实际内容。- 服务端接收到这些二进制数据后,调用
wektor[0].getName()会尝试访问客户端进程的内存地址,这个地址在服务端进程中是无效的,直接触发内存访问错误,导致程序崩溃。 - 基础类型的内存存储的就是值本身,所以直接传输二进制不会有问题。
解决方案:实现自定义类的序列化/反序列化
为data类重载QDataStream的输入输出运算符,让Qt正确处理对象的序列化:
1. 修改data.h,声明重载运算符
#ifndef DATA_H #define DATA_H #include <QtCore> class data { public: data(); void setName(QString name); QString getName(); // 声明QDataStream重载运算符 friend QDataStream& operator<<(QDataStream& out, const data& obj); friend QDataStream& operator>>(QDataStream& in, data& obj); private: QString Name; }; // 注册元类型(可选,若需在Qt信号槽中传递该类对象) Q_DECLARE_METATYPE(data) #endif // DATA_H
2. 修改data.cpp,实现运算符逻辑
#include "data.h" #include <QtCore> data::data() { this->Name = "null"; } void data::setName(QString name) { this->Name = name; } QString data::getName() { return this->Name; } // 序列化:将data对象写入QDataStream QDataStream& operator<<(QDataStream& out, const data& obj) { out << obj.Name; return out; } // 反序列化:从QDataStream读取data对象 QDataStream& operator>>(QDataStream& in, data& obj) { in >> obj.Name; return in; }
3. 修改客户端发送逻辑
去掉rozmiarSampla和ileSampli的传递,直接用QDataStream写入整个vector:
// 客户端发送部分替换为: QTcpSocket socket; socket.connectToHost("127.0.0.1",9999); if( !socket.waitForConnected() ) return 1; QDataStream stream(&socket); stream.setVersion(QDataStream::Qt_5_15); // 确保两端版本一致 QString typ("Paczka z buforem"); stream << typ << wektor; // 直接写入vector socket.flush(); socket.waitForBytesWritten();
4. 修改服务端接收逻辑
直接用QDataStream读取整个vector:
// 服务端接收部分替换为: QScopedPointer<QTcpSocket> socket{ serwer.nextPendingConnection() }; if(! socket->waitForReadyRead() ) return 1; QDataStream stream(socket.data()); stream.setVersion(QDataStream::Qt_5_15); // 和客户端版本保持一致 QString typ; stream >> typ >> wektor; // 直接读取vector
注意事项
- 客户端和服务端的
QDataStream版本必须一致,否则会出现序列化格式不兼容的问题。 - 如果
data类后续添加其他成员变量(如int、double等),需要在重载的operator<<和operator>>中同步添加对应的序列化逻辑。
内容的提问来源于stack exchange,提问作者TyTu
相关产品推荐
相关产品推荐

