QTcpServer如何真正监听连接

irp*_*pbc 8 qt 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...
}
Run Code Online (Sandbox Code Playgroud)

QTcpServer依赖于QCoreApplication(或者一个QRunLoop)现有和运行recive网络事件.它可以在没有QCoreApplication::exec()被叫的情况下正常工作吗?

irp*_*pbc 17

我一直在深入研究QtCoreQtNetwork模块的源代码.

通常,QTcpServer可以在两种模式下工作:同步异步.

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

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


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

waitForNewConnection()调用同步方法时,它只会绕过阻塞线程的所有QSocketNotifier内容和调用accept(),直到有传入连接.