我对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
)。此事件分派(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/