郭健豪 2024-04-17 11:50 采纳率: 50%
浏览 6

qt 使用线程池传输文件的时候,接受端在接收了一点点数据后就在执行readAll()时未响应了,调试的时候提示段错误

qt 使用线程池传输文件的时候,接受端在接收了一点点数据后就在执行readAll()时未响应了,调试的时候提示段错误。放在主线程接收的时候是可以正常接收的。

img

img

img

img

  • 写回答

6条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-17 11:50
    关注

    引自免费微信小程序:皆我百晓生

    根据您提供的信息,问题可能出现在多线程环境中对QTcpSocket的使用不当。在并发环境中,多个线程同时访问同一个QTcpSocket实例可能会导致竞态条件和数据同步问题。为了解决这个问题,您可以尝试将QTcpSocket对象封装在一个单独的类中,确保对它的所有操作都在一个线程内完成。此外,您还可以考虑使用信号槽机制处理网络事件,这样可以简化线程间的通信。

    首先,我们将创建一个新的类TcpConnectionHandler,它负责管理QTcpSocket的生命周期和读写操作。这个类将在一个单独的工作线程中运行。

    class TcpConnectionHandler : public QObject {
        Q_OBJECT
    public:
        explicit TcpConnectionHandler(QObject *parent = nullptr);
        ~TcpConnectionHandler();
    
        void startHandling(qintptr socketDescriptor);
    
    signals:
        void fileReceived(const QString &filePath);
        void connectionClosed();
    
    private slots:
        void onReadyRead();
        void onConnected();
        void onError(QAbstractSocket::SocketError error);
        void onDisconnected();
    
    private:
        QTcpSocket *m_socket;
        QDataStream m_stream;
    };
    

    接下来实现TcpConnectionHandler的成员函数:

    #include <QObject>
    #include <QTcpSocket>
    #include <QDataStream>
    #include <QFile>
    
    TcpConnectionHandler::TcpConnectionHandler(QObject *parent)
        : QObject(parent), m_socket(new QTcpSocket(this)), m_stream(m_socket)
    {
        connect(m_socket, &QTcpSocket::readyRead, this, &TcpConnectionHandler::onReadyRead);
        connect(m_socket, &QTcpSocket::connected, this, &TcpConnectionHandler::onConnected);
        connect(m_socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &TcpConnectionHandler::onError);
        connect(m_socket, &QTcpSocket::disconnected, this, &TcpConnectionHandler::onDisconnected);
    }
    
    TcpConnectionHandler::~TcpConnectionHandler()
    {
        if (m_socket->state() != QTcpSocket::UnconnectedState) {
            m_socket->close();
        }
        delete m_socket;
    }
    
    void TcpConnectionHandler::startHandling(qintptr socketDescriptor)
    {
        m_socket->setSocketDescriptor(socketDescriptor);
        m_socket->waitForConnected(-1);
    }
    
    void TcpConnectionHandler::onReadyRead()
    {
        quint64 filenameSize;
        QString fileInfo;
        quint64 fileSize;
    
        // 解析文件信息
        m_stream >> filenameSize >> fileInfo >> fileSize;
        received_file_size = fileSize;
    
        // 创建文件
        fileName = file_storage_address + fileInfo.mid(16);
        QFile file(fileName);
        if (!file.open(QIODevice::ReadWrite)) {
            emit connectionClosed();
            return;
        }
    
        while (file.isOpen()) {
            QByteArray data = m_socket->readAll();
            if (data.isEmpty()) {
                break;
            }
            file.write(data);
            received_file_size -= data.size();
        }
    
        if (fileSize == received_file_size) {
            file.close();
            emit fileReceived(fileName);
        } else {
            emit connectionClosed();
        }
    }
    
    void TcpConnectionHandler::onConnected()
    {
        qDebug() << "连接成功";
    }
    
    void TcpConnectionHandler::onError(QAbstractSocket::SocketError error)
    {
        qDebug() << "发生错误:" << error;
        emit connectionClosed();
    }
    
    void TcpConnectionHandler::onDisconnected()
    {
        qDebug() << "连接断开";
        emit connectionClosed();
    }
    

    现在,在Receive类中,我们不需要再使用线程池,而是创建一个TcpConnectionHandler实例并传递给工作线程:

    void Receive::run()
    {
        QEventLoop loop;
        TcpConnectionHandler handler(this);
    
        if (ip_address == "") {
            handler.startHandling(handle); // 服务器接收
        } else {
            QTcpSocket *socket = new QTcpSocket(this);
            socket->connectToHost(ip_address, 1880); // 客户端接受
            if (!socket->waitForConnected(-1)) {
                delete socket;
                return;
            }
            handler.m_socket->setSocketDescriptor(socket->socketDescriptor());
        }
    
        connect(&handler, &TcpConnectionHandler::fileReceived, this, &Receive::fileReceived);
        connect(&handler, &TcpConnectionHandler::connectionClosed, &loop, &QEventLoop::quit);
    
        loop.exec();
    }
    

    在这个修改后的版本中,Receive类不再直接操作QTcpSocket,而是通过TcpConnectionHandler来处理网络事件。这应该能解决你在多线程环境中遇到的问题。记得替换掉旧的代码,并重新编译和测试您的应用。如果还有其他问题,请随时告诉我。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月17日

悬赏问题

  • ¥20 大数据采集用Python爬取猫眼电影数据
  • ¥15 用freertos后NVIC里系统时钟部分报错
  • ¥15 后缀表达式的计算算法问题
  • ¥15 安装mid360驱动后,执行rviz_MID360.launch rviz不显示
  • ¥15 关于#人工智能#的问题:(2)设计一个GUI,允许语音和文本实现谣言的检测
  • ¥50 请教 麒麟系统挂载怎么安装
  • ¥15 如何在ns3中实现路径的自由切换
  • ¥20 SpringBoot+Vue3
  • ¥15 IT从业者的调查问卷
  • ¥65 LineageOs-21.0系统编译问题