Автоматическое переподключение клиента QTcpSocket

Я пытаюсь написать фрагмент кода, который периодически пытается подключиться к серверу с помощью QTcpSocket, пока сервер не будет готов. Клиент также должен автоматически и периодически пытаться переподключиться, когда сервер не работает, пока он снова не включится, или пользователь вручную не закроет программу.

Что я сделал, так это подписался на подключенные и ошибочные сигналы QTcpSocket. Когда я ловлю сигнал об ошибке, я снова вызываю метод connectToHost.

Мой код периодически пытается подключиться к хосту, пока сервер не будет готов (эта часть работает нормально). Однако проблема в том, что когда сервер не работает, он никогда не сможет восстановить соединение. Когда соединение не работает, я получаю RemoteHostClosedError, как и ожидалось. Но после повторного вызова метода connectToHost внутри того же метода (где я ловлю RemoteHostClosedError) я ничего не получил. Даже сигнал ошибки не выдается объектом QTcpSocket.

Я дал свой код ниже.

TcpServerConnector::TcpServerConnector( SocketSettings socketSettings, QObject* parent)
: QObject(parent), socket(new QTcpSocket())
{
    this->connect(this->socket, SIGNAL(connected()), this, SLOT(connectionSuccess_Handler()), Qt::DirectConnection);
    this->connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError_Handler(QAbstractSocket::SocketError)), Qt::DirectConnection);
}


void TcpServerConnector::connectionError_Handler( QAbstractSocket::SocketError error )
{
    switch (error)
    {
    case QAbstractSocket::AddressInUseError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Address is already in use");
        break;
    case QAbstractSocket::ConnectionRefusedError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Connection refused");
        break;
    case QAbstractSocket::HostNotFoundError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Host not found");
        break;
    case QAbstractSocket::RemoteHostClosedError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Remote host closed");            
        break;  
    }


    this->socket->abort();
    this->socket->close();
    this->logger.log(LogLevel::DEBUG, "Reconnecting...");
    SystemUtil::sleepCurrentThread(1000);
    this->socket->connectToHost(ip_address, port);
}

}

Я проверяю состояние QTcpSocket до и после вызова метода connectToHost (последняя строка, которую я здесь привел). Перед вызовом connectToHost состояние UnconnectedState, а после вызова connectToHost его состояние становится Connecting. Ничего неожиданного. Однако он не может ни подключиться к серверу, ни выдать сигнал об ошибке.

Любая идея?

Примечание. Метод connectToHost QTcpSocket вызывается внутри в первый раз.


person Furkan    schedule 22.07.2012    source источник
comment
Не подключайтесь повторно из слота обработчика ошибок. Когда этот сигнал испускается, сокет может быть не готов к попытке повторного подключения. документация qt   -  person bartolo-otrit    schedule 12.06.2015


Ответы (3)


Для тех, кто может столкнуться с подобной ситуацией, метод сброса QTcpSocket решил проблему.

person Furkan    schedule 22.07.2012
comment
Вы можете пометить свой ответ как правильный, когда будете решать задачи. Таким образом, тот, кто ищет это, быстро найдет решение. - person hg.; 23.07.2012
comment
не могли бы вы опубликовать свое решение ... Tnx;) - person Alireza Soori; 24.07.2013

Я был в этой ситуации, это решение:

    connect(&tcpClient, SIGNAL(disconnected()), SLOT(ReconnectToHost()));


    void ReconnectToHost(){tcpClient.connectToHost(theServerAddress, port);}
person user2572422    schedule 11.07.2013
comment
где отключен сигнал? Это по умолчанию или определяется пользователем? - person Sharath; 20.11.2013

Я столкнулся с такой проблемой. Что я сделал неправильно, так это то, что я попытался QTcpSocket::connectToHost() из слота моего класса, подключенного к сигналу QTcpSocket::error(). Наконец, я нашел решение в этой запись.

Если я не ошибаюсь, проблема в том, что вы не можете повторно подключиться из этого слота, потому что что-то важное происходит сразу после отправки сигнала QTcpSocket::error() и поток управления возвращается от вашего обработчика к методу QTcpSocket, который выдал этот сигнал, или поэтому вы как-то сломать логику сокета таким образом.

Не элегантное, но все же решение, состоящее из одной строки кода, заключается в вызове QMetaObject::invokeMethod(m_socket, "connectToHost", Qt::QueuedConnection); после вызова вашего слота handle_socket_error().

Остерегайтесь, если вы вызываете QMetaObject::invokeMethod в пользовательском методе, он должен быть зарегистрирован как слот.

UPD: к моему стыду, но эта проблема упоминается в документации Qt QAbstractSocket::error() signal .

person Veetaha    schedule 27.05.2018