QTcpServer如何真正地监听连接

时间:2012-07-26 08:28:13

标签: 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...
}

QTcpServer是否依赖于QCoreApplication(或者可能是QRunLoop)现有并且正在运行来回收网络事件。没有QCoreApplication::exec()被调用,它能正常工作吗?

2 个答案:

答案 0 :(得分:17)

我一直在浏览QtCoreQtNetwork模块的源代码。

很明显,QTcpServer可以使用两种模式:同步异步

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

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


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

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

答案 1 :(得分:0)

Qt的“幕后”功能大多发生在QCoreApplication的主要事件循环中:信号/插槽,定时器等。
一个例子是JavaScript - 您绑定一个事件,但事件循环由浏览器处理。