0

**** UPDATED:Windowsでのみsegfaultを取得したことに気付きました。 WindowsではQT 5.5とMinGW32を使用しています。私はまだ理由を知りたい。QNetworkAccessManager-> Post()を使用すると、アプリケーション終了時にSEGVが発生します。

****最初の質問: ここでは難しいことはありませんが、私は基本的なコンソールアプリケーションを作成します。 QNetworkAccessManagerがPost()リクエストを送信しています。コンソールを閉じると、segfaultがあります。

リクエストが正常に送受信されていることに注意してください。私の質問はそのsegfaultに関するものです。

Post()リクエストが送信されない場合、コンソールを閉じるときにクラッシュは発生しません。スタックからの助けはあまりありません。

スタック

0 ntdll!RtlFreeHeap   0x77b5e041 
1 ucrtbase!free   0x5e4c5eab 
2 LIBEAY32!CRYPTO_free   0x5e5a123e 

MAIN.CPP

#include <QCoreApplication> 
#include "CNetworkHandleTest.h" 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    CNetworkHandleTest net; 
    net.start(); 

    return a.exec(); 
} 

CNetworkHandleTest.cpp

#include "CNetworkHandleTest.h" 

CNetworkHandleTest::CNetworkHandleTest() 
{ 
    m_Manager = new QNetworkAccessManager(this); 
    // Connect the network manager so we can handle the reply 
    connect(m_Manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); 
    m_nTotalBytes = 0; 
} 

CNetworkHandleTest::~CNetworkHandleTest() 
{ 
    disconnect(); 
    m_Manager->deleteLater(); 
} 

void CNetworkHandleTest::onFinished(QNetworkReply* reply) 
{ 
    // Look at reply error 
    // Called when all the data is receivedqDebug() << "Error code:" << reply->error(); 
    qDebug() << "Error string:" << reply->errorString(); 
    reply->close(); 
    reply->deleteLater(); 
} 

void CNetworkHandleTest::start() 
{ 
    // Configure the URL string and then set the URL 
    QString sUrl(BASE_URL); 
    sUrl.append("/console/5555/upload"); 
    m_Url.setUrl(sUrl); 

    // Make the request object based on our URL 
    QNetworkRequest request(m_Url); 

    // Set request header (not sure how or why this works, but it works) 
    // \todo investigate 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlenconded"); 

    // Make file object associated with our DB file 
    QFile file("/tx_database.db"); 
    if(!file.open(QIODevice::ReadOnly)) 
    { 
     qDebug() << "Failed to open file"; 
    } 

    // Read the entire file as a binary blob 
    QByteArray data(file.readAll()); 

    // Set our request to our request object 
    // Note: there should probably be a flag so that when start is called it does not do 
    // any processing in case we are already in the middle of processing a request 
    m_Request = request; 

    // Send it 
    m_Reply = m_Manager->post(m_Request, data); 

    // Need to connect the signals and slots to the new reply object (manager makes a new 
    // reply object every post; may need to investigate if memory should be freed when 
    // done processing a response) 
    connect(m_Reply, SIGNAL(readyRead()), this, SLOT(onReadyRead())); 
    connect(m_Manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), 
      this,  SLOT(onAuthenticationRequired(QNetworkReply*, QAuthenticator*))); 
} 

void CNetworkHandleTest::onReadyRead() 
{ 
    // Whenever data becomes available, this slot is called. It is called every time data 
    // is available, not when all the data has been received. It is our responsibility to 
    // keep track of how much we have received if we want to show progress or whatever 
    // but we do not need to keep track if we have received all the data. The slot 
    // OnFinished will be called when the all the data has been received. 

    qDebug() << "Bytes available:" << m_Reply->bytesAvailable(); 
    m_nTotalBytes += m_Reply->bytesAvailable(); 
    qDebug() << "Bytes thus far:" << m_nTotalBytes; 
    QByteArray responseData = m_Reply->readAll(); 
    qDebug() << "Response" << responseData; 
    m_Reply->size(); 
} 

void CNetworkHandleTest::onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator) 
{ 

} 

CNetworkHandleTest.h

#ifndef CNETWORKHANDLETEST_H 
#define CNETWORKHANDLETEST_H 

// Required packages 
#include <QNetworkAccessManager> 
#include <QNetworkRequest> 
#include <QNetworkReply> 
#include <QByteArray> 
#include <QUrlQuery> 
#include <QHostInfo> 
#include <QObject> 
#include <QUrl> 

// Helper packages 
#include <QCoreApplication> 
#include <QFile> 
#include <QDir> 

// Our packages 
#include <iostream> 
#include <fstream> 
#include <cstdlib> 

#define BASE_URL "localhost:5000" 
#define BOUNDARY "123456787654321" 

class CNetworkHandleTest : public QObject 
{ 
    Q_OBJECT 

public: 
    CNetworkHandleTest(); 
    ~CNetworkHandleTest(); 

    void start(); 

protected Q_SLOTS: 

    void onFinished(QNetworkReply* reply); 
    void onReadyRead(); 
    void onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator); 

private: 

    QNetworkAccessManager* m_Manager; 
    QNetworkRequest  m_Request; 
    QNetworkReply*  m_Reply; 
    QUrl     m_Url; 

    int    m_nTotalBytes; 
}; 

#endif // CNETWORKHANDLETEST_H 
+0

あなたは 'onFinished()'からシグナルを出し、それをアプリケーションの 'quit()'スロットに接続することができます。転送が完了した後、アプリケーションを終了する必要があります。現在のところ、アプリケーションを終了すると、クラッシュの原因となる終了形式が発生する可能性があります。 –

+0

Windowsでのみsegfaultを取得したことに気付きました。Linuxではうまくいきます。 WindowsではQT 5.5とMinGW32を使用しています。私はまだ理由を知りたい。 – vincedjango

+1

ターミナルが閉じられたときに、ベースコードはおそらくシグナルを処理していないか、Windowsがプログラムを終了するために使用しているものではありません。 Linuxでは、標準信号であり、アプリケーションが正常に終了する可能性がありますが、Windowsではそうではない可能性があります。ウィンドウのシグナルクローズの方法を探している間にこれを見つけました:http://stackoverflow.com/questions/20511182/catch-windows-terminal-closing-on-running-process –

答えて

1

コンソールを閉じると、プログラムは最も悲観的に死ぬ。あなたは代わりにそれを優雅にするためにいくつかのコードを記述する必要があります。 以下の完全なテストケースである:あなたがCtrl + Cキーを押すか、コンソールウィンドウに[x]をクリックすると

// https://github.com/KubaO/stackoverflown/tree/master/questions/network-cleanup-40695076 
#include <QtNetwork> 
#include <windows.h> 

extern "C" BOOL WINAPI handler(DWORD) 
{ 
    qDebug() << "bye world"; 
    qApp->quit(); 
    return TRUE; 
} 

int main(int argc, char *argv[]) 
{ 
    SetConsoleCtrlHandler(&handler, TRUE); 
    QCoreApplication a(argc, argv); 

    QNetworkAccessManager mgr; 
    int totalBytes = 0; 

    QObject::connect(&mgr, &QNetworkAccessManager::finished, [](QNetworkReply *reply){ 
     qDebug() << "Error string:" << reply->errorString(); 
    }); 

    QNetworkRequest request(QUrl{"http://www.google.com"}); 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlenconded"); 

    auto reply = mgr.post(request, QByteArray{"abcdefgh"}); 
    QObject::connect(reply, &QIODevice::readyRead, [&]{ 
     qDebug() << "Bytes available:" << reply->bytesAvailable(); 
     totalBytes += reply->bytesAvailable(); 
     qDebug() << "Bytes thus far:" << totalBytes; 
     reply->readAll(); 
    }); 
    QObject::connect(reply, &QObject::destroyed, []{ 
     qDebug() << "reply gone"; 
    }); 
    QObject::connect(&mgr, &QObject::destroyed, []{ 
     qDebug() << "manager gone"; 
    }); 
    return a.exec(); 
} 

、シャットダウンが秩序ある、出力はされて:

[...] 
bye world 
reply gone 
manager gone 
関連する問題