2013-11-21 100 views
0

我的gui有兩個按鈕,一個啓動服務器&其他停止服務器。QTcpServer - 如何停止客戶端線程

Brief:---
一旦服務器啓動後,在每一個新的客戶端請求我將創建一個新的線程&這將處理與客戶的溝通。

Detail: -
當按下start button,我創建一個對象「tcpserverobjectWrapper」,這將創建一個另一個對象「tcpserverobject」這個對象及牡丹QTcpServer既可。 現在這個Qtcpserver列出了新的連接。當一個新的連接到來時,我創建了一個'TcpSocketThreadWrapperObject'對象,其中 創建線程&此線程處理與客戶端的通信。還'tcpserverobject'保留創建新客戶端請求對象列表 'QList<TcpSocketThreadWrapperObject *> TcpSocketThreadWrapperObjectList;'。

我能夠從telnet客戶端&連接到服務器時,它爲&工作正常,每個客戶端創建新的線程。

stop button按下時,我可以停止服務器&客戶端線程。

但是我有two problems這裏:---
1>每次客戶端發送一些數據到服務器。我得到這種QsocketNotifier。這是什麼 ?

QSocketNotifier: socket notifiers cannot be enabled from another thread 
QSocketNotifier: socket notifiers cannot be disabled from another thread 

2>如果我按下GUI上的停止按鈕,我可以成功地停止線程。

但是如何停止線程&當客戶端發送'STOP command'到服務器或closes the connection與服務器時刪除爲每個客戶端創建的對象?
我還必須刪除在每個客戶端請求上創建的以下對象?
客戶端請求 - > TcpSocketThreadWrapperObject - 創建 - > TcpSocketThreadObject - 創建 - > TcpSocketThreadObject

有人可以建議如何解決以上兩個問題?對此的回覆將不勝感激。

下面是代碼:---

=================開始&停止按鈕處理程序=====

void MainWindow::on_actionStop_triggered() 
{ 
    if(b_threadAlreadyStarted) 
    { 

    /* ------------------ Tcp server object ------------------------*/ 

     b_threadAlreadyStarted = false; 
     delete p_tcpserverobjectWrapper; 

    /* ------------------ Tcp server object ------------------------*/ 

    } 

} 



void MainWindow::on_actionStart_triggered() 
{ 

    if(!b_threadAlreadyStarted) 
    { 

    /* ------------------ Tcp server object ------------------------*/ 

     b_threadAlreadyStarted =true; 

     p_tcpserverobjectWrapper = new tcpserverobjectWrapper(this,modelCANalyzer); 

     qDebug() << " \n start "; 

    /* ------------------ Tcp server object ------------------------*/ 

    } 
} 

======== tcpserverobjectWrapper類===============

// Main server object wrapper 
class tcpserverobjectWrapper : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit tcpserverobjectWrapper(QMainWindow *ptrWidget, QStandardItemModel *modelCANalyzer, QObject *parent=0); 
    ~tcpserverobjectWrapper(); 

    //Device thread object 
    tcpserverobject *m_tcpserverobject; 
}; 



tcpserverobjectWrapper::tcpserverobjectWrapper(QMainWindow *ptrWidget , QStandardItemModel *modelCANalyzer,QObject *parent) : 
    QObject(parent) 
{ 
    m_tcpserverobject = new tcpserverobject ; 

    //save model 
    m_tcpserverobject->modeltable = modelCANalyzer; 
    m_tcpserverobject->ptrmainwindow = ptrWidget; 


    qDebug() << "\n tcp server thread started"; 

} 

tcpserverobjectWrapper::~tcpserverobjectWrapper() 
{ 

    qDebug() << " \n called delete later on tcpserverobjectWrapper .. !!"; 

    m_tcpserverobject->deleteLater(); // ---------------------> change it to - delete m_tcpserverobject 

    qDebug() << " \n tcp server object successfully quited .. !! "; 
} 

========== tcpserverobject對象====== ============

class tcpserverobject : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit tcpserverobject(QObject *parent = 0); 
    ~tcpserverobject(); 

    /*! 
     Pointer to QStandardItemModel to be used inside - canTableView 
    */ 
    QStandardItemModel *modeltable; 

    //mainwindow pointer 
    QMainWindow *ptrmainwindow; 

    // Create list of new -- socket thread wrapper objects 
    QList<TcpSocketThreadWrapperObject *> TcpSocketThreadWrapperObjectList; 

private: 
    QTcpServer *tcpServer; 

signals: 

public slots: 

    void on_newConnection(); 

}; 

tcpserverobject::tcpserverobject(QObject *parent) : 
    QObject(parent), tcpServer(0) 
{ 
    tcpServer = new QTcpServer; 

    // Connect slot of the server 
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(on_newConnection())); 

    //lisen on socket 
    if (!tcpServer->listen(QHostAddress::LocalHost, SERVER_PORT)) { 

     qDebug() << "\n returning from server listning error .. !!! "; 

     return; 
    } 

    qDebug() << "\n server listning"; 

} 

tcpserverobject::~tcpserverobject() 
{ 

    // to do 
    while (!TcpSocketThreadWrapperObjectList.isEmpty()) 
     delete TcpSocketThreadWrapperObjectList.takeFirst(); 
} 

void tcpserverobject::on_newConnection() 
{ 
    QByteArray block; 

    block.append(" \n Hello from server .. !!!") ; 

    QTcpSocket *clientConnection = tcpServer->nextPendingConnection(); 
    connect(clientConnection, SIGNAL(disconnected()), 
       clientConnection, SLOT(deleteLater())); 

    // Create new thread for this .. client request ..!! 
    qDebug() << "\n New connection request ..!!!"; 
    qDebug() << "\n New client from:" << clientConnection->peerAddress().toString(); 

    clientConnection->write(block); 
    clientConnection->flush(); 

    // create new tcp object 
    TcpSocketThreadWrapperObject* TcpSocketThreadWrapperObjectPtr = new TcpSocketThreadWrapperObject(clientConnection); 

    // Append object to the list 
    TcpSocketThreadWrapperObjectList.append(TcpSocketThreadWrapperObjectPtr); 

} 

============ TcpSocketThreadWrapperObject ==============

// Main device thread object 
class TcpSocketThreadWrapperObject : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit TcpSocketThreadWrapperObject(QTcpSocket *m_pTcpSocket , QObject *parent = 0); 
    ~TcpSocketThreadWrapperObject(); 

    /*! 
     pointer for write thread 
    */ 
    QThread m_TcpSocketRWThread; 

    /// pointer to the socketthread object 
    class TcpSocketThreadObject *m_pTcpSocketThreadObject; 


signals: 

public slots: 

}; 


// constructor for the deviceThreadObject 
TcpSocketThreadWrapperObject::TcpSocketThreadWrapperObject(QTcpSocket *m_pTcpSocket , QObject *parent) : 
    QObject(parent) 
{ 
    m_pTcpSocketThreadObject = new TcpSocketThreadObject(m_pTcpSocket); 

    //set flag for event loop -- make while(1) 
    m_pTcpSocketThreadObject->m_bQuit = false; 
    // connect the signal & slot 
    connect(&m_TcpSocketRWThread,SIGNAL(started()),m_pTcpSocketThreadObject,SLOT(dowork_socket())); 
    // Move thread to object 
    m_pTcpSocketThreadObject->moveToThread(&m_TcpSocketRWThread); 

    //Start the thread 
    m_TcpSocketRWThread.start(); 

} 

TcpSocketThreadWrapperObject::~TcpSocketThreadWrapperObject() 
{ 

    //set flag for event loop -- make while(0) 
    m_pTcpSocketThreadObject->m_bQuit = false; 

    // Wait for the thread to terminate 
    m_TcpSocketRWThread.quit(); 
    m_TcpSocketRWThread.wait(); 

    // Delete the object 
    m_pTcpSocketThreadObject->deleteLater(); 

    qDebug() << "\n deleted - TcpSocketThreadWrapperObject"; 

} 

======== TcpSocketThreadObject對象== ======

class TcpSocketThreadObject : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit TcpSocketThreadObject(QTcpSocket *m_pTcpSocketTemp , QObject *parent = 0); 
    ~TcpSocketThreadObject(); 

    /*! 
     Pointer to TCP socket -- created by the server 
    */ 
    QTcpSocket *m_pclientConnectionSocket; 


    /*! 
     Termination control main thread 
    */ 
    volatile bool m_bQuit; 

signals: 

public slots: 
    void dowork_socket(); 

}; 


// constructor for the deviceThreadObject 
TcpSocketThreadObject::TcpSocketThreadObject(QTcpSocket *m_pTcpSocketTemp , QObject *parent) : 
    QObject(parent) 
{ 
    m_pclientConnectionSocket = m_pTcpSocketTemp; 

    // todo 
} 

TcpSocketThreadObject::~TcpSocketThreadObject() 
{ 
    // todo 

} 

void TcpSocketThreadObject::dowork_socket() 
{ 
    QByteArray block; 

    block.append(" \n hi again .. !!!") ; 

    // Write to socket 
    m_pclientConnectionSocket->write(block); 
    m_pclientConnectionSocket->flush(); 

    // Close socket 
    m_pclientConnectionSocket->disconnectFromHost(); 
    qDebug() << "\n entring loop of socket thread ..!!!"; 

    while(!m_bQuit) 
    { 
     // while loop --> send/rx command from client 
    } 

} 

連接到服務器=====一個客戶端的=======輸出

New connection request ..!!! 

New client from: "127.0.0.1" 
QSocketNotifier: socket notifiers cannot be enabled from another thread 
QSocketNotifier: socket notifiers cannot be disabled from another thread 

entring loop of socket thread ..!!! 

回答

0

我覺得這一切最簡單的解決方法是停止使用QThread。

QTcpSocket和QTcpServer都是異步的,所以當你接收到一個連接時,你只需要創建一個包裝QTcpSocket的類,並且該類將QTcpSocket信號連接到類的插槽來處理數據的讀取。

如果您獲得了很多連接,那麼您將創建大量線程。比處理器內核更多的線程只是浪費時間。

如果每個連接都要求服務器完成很多工作,則可以創建單獨的工作對象並將它們移動到不同的線程,但總體而言,我建議您不要爲QTcpServer使用單獨的線程, QTcpSockets。