Как 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...
}

Is QTcpServer зависит от QCoreApplication (или QRunLoop) существующие и запущенные для получения сетевых событий. Может ли он работать правильно без QCoreApplication::exec() вызывается?

2 ответов


я просверлил исходный код QtCore и QtNetwork модули.

Aperantly, QTcpServer может работать в двух режимах: синхронно и асинхронные.

на синхронно режим после вызова listen() абонент может позвонить waitForNewConnection() который является методом блокировки (поток будет спать, пока кто-то не подключится к порту прослушивания). Таким образом QTcpServer может работать в потоке без события петля.

на асинхронные режим QTcpServer будет излучать newConnection() сигнал, когда новое соединение было принято. Но для этого должен быть запущен цикл событий. В основе QCoreApplication это QEventLoop и QAbstractEventDispatcher (абстрактный класс, конкретный тип зависит от ОС, например QEventDispatcherUNIX). Этот диспетчер событий может отслеживать состояние сокетов (представленных файловыми дескрипторами). У него есть метод registerSocketNotifier(QSocketNotifier*). Этот метод вызывается конструктор QSocketNotifier класса,QTcpServer создает экземпляр every time listen() называется. Единственный системный вызов, который вызывается, когда QTcpServer::listen() вызывается, конечно, listen() который сразу же возвращается, вся настоящая магия происходит, когда начинается цикл событий. Цикл событий (с помощью диспетчера) будет отслеживать, есть ли определенное условие для зарегистрированных сокетов. Он называет select() системный вызов, который получает один или несколько файлов дескрипторы, которые будут отслеживаться (ядром) для определенных условий (если есть данные для чтения, если данные могут быть записаны или если произошла ошибка). Вызов может блокировать поток до тех пор, пока не будут выполнены условия на сокетах, или он может вернуться через некоторое время, когда условия на сокетах не были выполнены. Я не уверен, что Qt вызывает select() С предоставленным временем ожидания или без (блокировать бесконечно), я думаю, что это определяется каким-то сложным образом и изменчивым. Так когда? наконец, условие на сокете было выполнено, диспетчер событий уведомит QSocketNotifier для этого сокета, который, в свою очередь, уведомить QTcpServer кто слушает сокет, который примет соединение и испустит newConnection() сигнал.


так QTcpServer сам не вызывает систему мониторинга событий/сокетов, но зависит от нее через QSocketNotifier, который он использует для асинхронного получения соединений.

когда синхронно метод waitForNewConnection() называется он просто обходит все QSocketNotifier материал и называет accept(), который блокирует поток, пока есть соединение.


большинство функций Qt "за кулисами" происходит внутри основного цикла событий QCoreApplication: сигналы/слоты, таймеры и т. д.
Примером может быть JavaScript-вы связываете событие, но цикл событий обрабатывается браузером.