2016-02-05 82 views
0

我正在爲客戶端/服務器應用程序編寫客戶端。客戶端應該使用登錄窗口進行登錄。如果登錄成功,將出現「等待」窗口(這只是一個包含標籤的窗口)。在服務器端有一個障礙,等待n個客戶端登錄;當發生這種情況時,廣播一條消息,等待窗口應該關閉,併爲每個客戶端出現一個新窗口。Qt創建一個等待網絡事件的對話框

網絡接口由我使用低級函數實現,而不是由Qt提供的功能。

實際等待循環是這樣的:

char buffer[256]; 
while (strcmp(buffer, "proceed")) 
    read(sockfd, buffer, 256); 

的問題是,如果我開始這個循環在主線程,應用程序會阻止,原因是顯而易見的。

如何讓此循環運行並且不阻止應用程序,並在結束時關閉對話框?

後來編輯:我也嘗試使用QThreads,但是,對於原因,我不完全理解的是,應用程序仍然崩潰:

class WaitLoop : public QThread { 
public: 
    WaitLoop(NetworkHandler &network) : network(network) {} 
private : 
    NetworkHandler &network; 
    void run() { 
     this->network.waitForGameStart(); 
    } 
}; 

在等待對話框構造函數:

WaitLoop *waitLoop = new WaitLoop(network); 
connect(waitLoop, SIGNAL(finished()), this, SLOT(gameStartSlot())); 
waitLoop->start(); 

應用程序仍然使用這種方法崩潰。

+0

也許一個進度對話框可以工作; http://doc.qt.io/qt-4.8/qprogressdialog.html –

+0

實現具有此功能的工作對象並在單獨的線程中運行。當您收到該消息時,只需從工作對象發出一個信號,您可以連接到該對話框的「close()」插槽。 – ramtheconqueror

+0

@ramtheconqueror現在你有兩個問題,而不是一個。線程不是普遍的補救措施。 –

回答

0

最簡單的方法來處理此問題將不會使用低級別的函數,因爲你不寫在C中。至少使用QAbstractSocket來包裝sockfdsetSocketDescriptor方法可以讓你做到這一點。

那麼你的代碼變得非阻塞和異步:

class Controller : public QObject { 
    Q_OBJECT 
    QStateMachine m_sm; 
    QState s_init{&m_sm}, s_proceeding{&m_sm}; 
    QAbstractSocket m_socket; 
    Q_SIGNAL void proceed(); 
    Q_SLOT void onData() { 
    auto data = m_socket.readAll(); 
    if (data.contains("proceed")) proceed(); 
    } 
public: 
    Controller(QObject * parent = 0) : QObject(parent) { 
    connect(&m_socket, &QIODevice::readyRead, this, &Controller::onData); 
    s_init.addTransition(this, &Controller::proceed, &s_proceeding); 
    m_sm.setInitialState(&s_init); 
    m_sm.start(); 
    } 
    bool setup(quintptr fd) { 
    return m_socket.setSocketDescriptor(fd); 
    } 
}; 

通過使用狀態機,可以很容易地添加更多的國家,去應對轉變(見QState::onEntry信號等),以及確保行爲正確。充實UML狀態圖迫使您考慮處理角落案例等。完整示例請參見this answer

+0

我知道這是最佳做法,將低級網絡處理例程與高級代碼組合起來並不是最好的方法。但是,這是應用程序的一個要求,即使用低級網絡處理例程。 – Paul92

+0

@ Paul92然後,將網絡中使用的文件描述符與事件循環集成。你的圖書館,如果設計得當,應該給用戶一套文件描述符,並讓用戶在檢測到任何活動時通知* it *。然後你的Qt代碼將使用一個'QSocketNotifier'來回調你的庫,其他人的代碼可能會使用glib的事件循環,或者只是一個簡單的'poll'或者shudder'select'。否則,把它全部放到一個線程中。我不知道你做錯了什麼,你沒有顯示足夠的代碼。 –