2012-07-26 133 views
8

我對QTcpServer如何在線程和阻塞的幕後工作感興趣。 QTcpServer有一個listen()方法立即返回。如果收聽成功,服務器將發出信號newConnection()。我感興趣的是當listen()方法返回時,服務器如何監聽(是否在主線程中)。有QTcpServer既可控制檯應用程序的普通的一個例子是這樣的:QTcpServer如何真正監聽連接

//main.cpp 
int main(int argc, char* argv[]) 
{ 
    QCoreApplication app; 
    MyServer server; 
    app.exec(); 
} 

//MyServer.cpp 
MyServer::MyServer(QObject *parent) : QObject(parent) 
{ 
    this->server = new QTcpServer(this); 
    connect(server, SIGNAL(newConnection()), this, SLOT(on_newConnection())); 
    if (!server->listen(QHostAddress::Any, 1234)) 
     //do something in case of error 
} 
void MyServer::on_newConnection() 
{ 
    QTcpSocket* socket = server->nextPendingConnection(); 
    //do some communication... 
} 

QTcpServer依賴於QCoreApplication(或者一個QRunLoop)現有和運行recive網絡事件。如果沒有調用QCoreApplication::exec(),它可以正常工作嗎?

回答

16

我一直在鑽取QtCoreQtNetwork模塊的源代碼。

Aperantly,QTcpServer可在兩種模式下工作:同步異步

同步模式調用listen()呼叫者可以調用waitForNewConnection()其是阻塞方法之後(該線程將休眠直到有人連接到收聽端口)。這樣QTcpServer可以在沒有事件循環的線程中工作。

異步模式QTcpServer將發出newConnection()信號,當一個新的連接被接受。但爲了能夠做到這一點,必須有一個事件循環運行。底層的QCoreApplicationQEventLoopQAbstractEventDispatcher(抽象類,具體類型取決於操作系統,例如QEventDispatcherUNIX)。此事件調度程序可以監視套接字上的條件(由文件描述符表示)。它有一個方法registerSocketNotifier(QSocketNotifier*)。此方法由QSocketNotifier類的構造函數調用,其中QTcpServer創建每次調用listen()的實例。調用QTcpServer::listen()時調用的唯一系統調用當然是listen(),它只是立即返回,當事件循環開始運行時,所有真正的魔法都會發生。事件循環(使用調度程序)將監視在已註冊的套接字上是否存在特定條件。它調用系統調用,在某些情況下(如果有數據要讀取,如果數據可以寫入,或者發生錯誤)接收一個或多個文件描述符(由內核)進行監視。該調用可以阻塞該線程,直到滿足套接字的條件,或者在經過一段時間之後它可以返回並且不符合套接字上的條件。我不確定Qt是否提供了帶有或不帶有等待時間(無限期阻止)的select(),我認爲這是以一種複雜的方式確定並且可以改變的。因此,當最終滿足套接字條件時,事件調度程序將通知該套接字QSocketNotifier,該套接字將通知正在偵聽套接字的QTcpServer誰將接受連接併發出newConnection()信號。


所以QTcpServer本身不調用到事件環/插座監測系統,但它通過它用來連接異步recieving的QSocketNotifier依賴於它。

當同步方法waitForNewConnection()被稱爲它只是繞過所有的QSocketNotifier的東西,並呼籲accept()阻止線程,直到有一個傳入的連接。

+0

非常好。現在我明白爲什麼在執行Qt中的應用程序事件循環之前調用listen(我使用PyQt)確實沒有得到'newConnection'信號。感謝您的挖掘。 – Trilarion 2015-10-20 21:28:24

0

大多數Qt的功能發生QCoreApplication的主要事件循環裏面的「幕後」的:信號/插槽,定時器等
一個例子是JavaScript的 - 你綁定的事件,但事件循環是由瀏覽器處理。