Pergunta

Estou interessado em saber como o QTcpServer funciona nos bastidores em relação a threads e bloqueios. QTcpServer tem um listen() método que retorna imediatamente.Se a escuta for iniciada com sucesso, o servidor emitirá o sinal newConnection().Estou interessado em saber como o servidor está escutando (está no thread principal) quando o listen() método retornou.O exemplo usual de um aplicativo de console com QTcpServer é mais ou menos assim:

//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 dependente de um QCoreApplication (ou talvez um QRunLoop) existente e em execução para receber eventos de rede.Pode funcionar corretamente sem um QCoreApplication::exec() sendo chamado?

Foi útil?

Solução

Estive analisando o código-fonte do QtCore e QtNetwork módulos.

Aparentemente, QTcpServer pode funcionar em dois modos: síncrono e assíncrono.

Em síncrono modo depois de ligar listen() o chamador pode ligar waitForNewConnection() que é um método de bloqueio (o thread ficará suspenso até que alguém se conecte à porta de escuta).Por aqui QTcpServer pode funcionar em um thread sem um loop de eventos.

Em assíncrono modo QTcpServer emitirá o newConnection() sinal quando uma nova conexão foi aceita.Mas para poder fazer isso, deve haver um loop de eventos em execução.Subjacente ao QCoreApplication são as QEventLoop e QAbstractEventDispatcher (uma classe abstrata, tipo concreto depende do sistema operacional, por exemplo QEventDispatcherUNIX).Este despachante de eventos pode monitorar condições em soquetes (representados por descritores de arquivo).Tem um método registerSocketNotifier(QSocketNotifier*).Este método é chamado pelo construtor do QSocketNotifier aula, que QTcpServer cria uma instância de cada vez listen() é chamado.A única chamada de sistema que é chamada quando o QTcpServer::listen() é invocado é, claro, listen() que retorna imediatamente, toda a verdadeira mágica acontece quando o loop de eventos começa a ser executado.O loop de eventos (usando o despachante) monitorará se há uma determinada condição nos soquetes que foram registrados.Ele chama o select() chamada de sistema que recebe um ou mais descritores de arquivo a serem monitorados (pelo kernel) para determinadas condições (se há dados para serem lidos, se os dados podem ser gravados ou se ocorreu um erro).A chamada pode bloquear o thread até que as condições nos soquetes sejam atendidas ou pode retornar após algum tempo e as condições nos soquetes não forem atendidas.Não tenho certeza se o Qt está ligando select() com tempo de espera fornecido ou sem (para bloquear indefinidamente), acho que é determinado de alguma forma complicada e mutável.Então, quando finalmente a condição no soquete for atendida, o despachante do evento notificará o QSocketNotifier para esse soquete, que irá, em tern, notificar o QTcpServer quem está ouvindo o soquete, que aceitará a conexão e emitirá o newConnection() sinal.


Então o QTcpServer não chama o sistema de loop de eventos/monitoramento de soquete, mas depende dele por meio do QSocketNotifier que ele usa para recebimento assíncrono de conexões.

Quando método síncrono waitForNewConnection() é chamado, apenas ignora todos os QSocketNotifier coisas e chamadas accept() que bloqueia o thread até que haja uma conexão de entrada.

Outras dicas

A maior parte da funcionalidade "nos bastidores" do Qt acontece dentro do loop de eventos principal do QCoreApplication:sinais/slots, temporizadores, etc.
Um exemplo seria JavaScript - você vincula um evento, mas o loop de eventos é processado pelo navegador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top