QTcpServer如何真正地监听连接

我对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(),它可以正常工作吗?

我一直在深入研究QtCore和QtNetwork模块的源代码.

很明显,QTcpServer可以在两种模式下工作:同步和异步.

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

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

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

当同步方法waitForNewConnection()被调用时,它只是绕过所有QSocketNotifier的东西并调用accept()来阻塞线程,直到有一个传入的连接.

翻译自:https://stackoverflow.com/questions/11665293/how-is-qtcpserver-really-listening-for-connections

转载注明原文:QTcpServer如何真正地监听连接