You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:31:05