我对QTcpServer在线程和阻塞方面的幕后工作方式感兴趣。 QTcpServer具有listen()方法,该方法可立即返回。如果成功开始监听,则服务器将发出信号newConnection()。我对listen()方法返回后服务器如何监听(是否在主线程上)感兴趣。带有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)。无需调用QCoreApplication::exec()就能正常工作吗?

最佳答案

我一直在研究QtCoreQtNetwork模块的源代码。

正确地讲,QTcpServer可以在两种模式下工作:同步异​​步

在调用listen()之后,在同步模式下,调用者可以调用waitForNewConnection(),这是一种阻塞方法(线程将休眠,直到有人连接到监听端口为止)。这样QTcpServer可以在没有事件循环的情况下在线程中工作。

异​​步模式下,当接受新连接时,QTcpServer将发出newConnection()信号。但是要做到这一点,必须有一个事件循环运行。 QCoreApplication的基础是QEventLoopQAbstractEventDispatcher(抽象类,具体类型取决于OS,例如QEventDispatcherUNIX)。此事件分派(dispatch)器可以监视套接字上的条件(由文件描述符表示)。它具有registerSocketNotifier(QSocketNotifier*)方法。该方法由QSocketNotifier类的构造函数调用,QTcpServer在每次调用listen()时都会创建一个实例。当然,当调用QTcpServer::listen()时,唯一被调用的系统调用是listen(),它立即返回,所有真正的魔术发生在事件循环开始运行时。事件循环(使用调度程序)将监视已注册的套接字上是否存在特定条件。它调用 select() 系统调用,该系统调用接收一个或多个文件描述符,这些描述符在某些情况下(由内核)监视(如果有要读取的数据,可以写入的数据或发生错误)。该调用可以阻塞线程,直到满足套接字上的条件为止,或者可以在经过一定时间并且不满足套接字上的条件后返回该线程。我不确定Qt是否在提供等待时间的情况下调用select()或不提供(无限期阻止),我认为它以某种复杂的方式确定并且可变。因此,当最终满足套接字上的条件时,事件分发程序将通知该套接字的QSocketNotifier,然后将其通知正在监听套接字的QTcpServer,后者将接受连接并发出newConnection()信号。

因此,QTcpServer本身并不调用事件循环/套接字监视系统,而是通过QSocketNotifier依赖于它,它用于异步接收连接。

调用同步方法waitForNewConnection()时,它会绕过所有QSocketNotifier内容,并调用accept(),它将阻塞线程,直到有传入连接为止。

关于qt - QTcpServer如何真正监听连接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11665293/

10-13 02:45