Как QTcpServer на самом деле прослушивает соединения

StackOverflow https://stackoverflow.com//questions/11665293

  •  11-12-2019
  •  | 
  •  

Вопрос

Меня интересует, как 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 (абстрактный класс, конкретный тип зависит от ОС, например QEventDispatcherUNIX).Этот диспетчер событий может отслеживать состояние сокетов (представленных файловыми дескрипторами).У него есть метод registerSocketNotifier(QSocketNotifier*).Этот метод вызывается конструктором QSocketNotifier класс, который QTcpServer создает экземпляр каждый раз listen() называется.Единственный системный вызов, который вызывается, когда QTcpServer::listen() вызывается, конечно, listen() который просто немедленно возвращается, вся настоящая магия происходит, когда начинает работать цикл событий.Цикл событий (с использованием диспетчера) будет отслеживать наличие определенного условия для зарегистрированных сокетов.Он называет select() системный вызов, который получает один или несколько дескрипторов файлов, которые должны отслеживаться (ядром) при определенных условиях (если есть данные для чтения, если данные могут быть записаны или произошла ошибка).Вызов может заблокировать поток до тех пор, пока не будут выполнены условия для сокетов, или он может вернуться после того, как пройдет некоторое время и условия для сокетов не будут выполнены.Я не уверен, звонит ли Qt select() с указанием времени ожидания или без него (блокировать на неопределенный срок), я думаю оно определяется каким-то сложным образом и изменяемо.Поэтому, когда наконец условие сокета будет выполнено, диспетчер событий уведомит об этом QSocketNotifier для этого сокета, который, в свою очередь, уведомит QTcpServer кто слушает сокет, который примет соединение и выдаст newConnection() сигнал.


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

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

Другие советы

Большинство Qt's "за сценами" функциональность происходит внутри основного цикла событий QcoReApplication: сигналы / слоты, таймеры и т. Д.









Примером будет JavaScript - привязываете событие, но цикл событий обрабатывается браузером.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top