Опция сохранения активности QTcpSocket не работает

У меня есть простая программа в качестве моего клиента, состоящая из tcp-сокета (QTcpSocket). Коды для моего клиента приведены ниже:

while (tcpSocket.data()->waitForConnected(maxWaitingTimeToConnect) == false)
{
    tcpSocket.data()->connectToHost(serverIP, serverPort);
    if (maxRetryNumberToConnect != -1 && retryNumber++ > maxRetryNumberToConnect)
    {
        qDebug() << "Socket is disconnected and maximum try for re-connection reached.";
        return false;
    }
    emit sgl_tryToConnect();
    // Socket is disconnected and trying to re-connect
    QThread::msleep(100);
}
qDebug() << "Client is connected";
qDebug() << tcpSocket.data()->localPort();
auto sd = tcpSocket.data()->socketDescriptor();
NetworkShared::setSocketOption(&sd);

который setSocketOption также указан ниже:

/// Set keepAlive
int enableKeepAlive = 1;
/* Set socket FD's option OPTNAME at protocol level LEVEL
   to *OPTVAL (which is OPTLEN bytes long).
   Returns 0 on success, -1 for errors.  */
qDebug() << setsockopt(*socketDescriptor, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));

int maxIdle = 1; /// Seconds
qDebug() << setsockopt(*socketDescriptor, SOL_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));

int count = 1;  /// Send up to 1 keepalive packets out, then disconnect if no response
qDebug() << setsockopt(*socketDescriptor, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));

int interval = 1;  /// Send a keepalive packet out every 1 seconds (after the 1 second idle period)
qDebug() << setsockopt(*socketDescriptor, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));

когда я запускаю свою программу, все выглядит нормально, и для моего сокета будет включена опция поддержания активности. Но это не работает, когда я отключаю кабель на стороне клиента. Ниже я привел свой вывод netstat, который указывает, что таймер поддержки активности включен для моего сокета.

tcp        0      0 192.168.2.157:37281     192.168.2.163:4444      ESTABLISHED keepalive (0.16/0/0)

Я также включил опцию поддержки активности на стороне сервера точно так же, как на стороне клиента. Теперь у меня есть несколько вопросов; 1- Когда я должен включить опцию поддержки активности? После подключения к серверу или перед подключением? 2- Должен ли я написать код для обнаружения ошибки поддержки активности в моей программе?

Кстати, моя программа работает в Linux Mint 17.1, и я также изменил параметры keeplalive в sysctl.conf и proc/sys на no vail.

Заранее спасибо за вашу помощь. Реза


person Reza    schedule 20.12.2016    source источник
comment
Опубликованный вами вывод netstat указывает на то, что он работает. Непонятно, что вы спрашиваете.   -  person user207421    schedule 20.12.2016
comment
Вы ссылались на этот сигнал QAbstractSocket::disconnected(), который не испускается при переключении отключен. В качестве альтернативы вы также можете подумать об использовании различных методов waitfor...() (например, waitForReadyRead(milliseconds)). Время ожидания может быть установлено на желаемое значение, и в течение этого времени также проверьте, активно ли соединение. Кстати, я новичок в Qt. Вы нашли решение вашей актуальной проблемы? @EJP, я думаю, что у OP есть проблема, когда розетка не отключается, даже когда интернет-штекер вытащен (если я правильно понял).   -  person iammilind    schedule 18.05.2017


Ответы (1)


Было бы лучше использовать функцию Qt setSocketOption:

your_socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);

перечисление QAbstractSocket::SocketOption

Это перечисление представляет параметры, которые можно установить для сокета. При желании их можно установить после получения сигнала connect() от сокета или после получения нового сокета от QTcpServer.

Примечание. В среде выполнения Windows параметр QAbstractSocket::KeepAliveOption должен быть установлен до подключения сокета.

и для обнаружения любых ошибок подключения:

connect (your_socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), this, &YourClass::onError);
// ...

void YourClass::onError(QAbstractSocket::SocketError socketError)
{
    switch(socketError)
    {
        case QAbstractSocket::ConnectionRefusedError:
        // ...
        // ...
    }
}
person Vladimir Bershov    schedule 20.12.2016
comment
Лучше бы почему? - person user207421; 20.12.2016
comment
@EJP, потому что у Qt для этого есть свои функции, и в этом случае странно смешивать Qt и системные функции. Также Qt является кроссплатформенным фреймворком. - person Vladimir Bershov; 20.12.2016
comment
Не имеющий отношения. Если setsockopt() не возвращает -1, это явно сработало, так как именно это решит проблему ОП? - person user207421; 20.12.2016
comment
setsocket возвращает 0, что означает, что это правда. Я также пробовал setSocketOption, предоставленный Qt, но это не решило мою проблему. Кроме того, как я могу установить другие параметры, такие как время простоя с этой функцией? Это только включает опцию поддержки активности. - person Reza; 20.12.2016
comment
@VladimirBershov Я также подключаю ошибку сокета точно так же, как предложенный вами код, но в моем случае это не работает. Когда я отключаю свой кабель, сервер понимает это, а клиентская сторона - нет. Я думаю, что моя проблема заключается в значениях, которые я установил для своего сокета. - person Reza; 20.12.2016
comment
@Reza На этой странице нет ничего, что указывало бы на то, что у вас вообще есть проблема, и я сказал об этом час назад. Вам нужно заняться этим. - person user207421; 20.12.2016
comment
@EJP Думаю, я ясно сказал о своей проблеме. Мой сокет на стороне клиента не понимает обрыв соединения из-за отключения сетевого кабеля. Я могу поймать другие ошибки сокета до и после повторного подключения. Так что я почти уверен, что мой код правильный. Пожалуйста, взгляните на вывод активности netstat (0.16/0/0). Когда я отключаю кабель, первая цифра начинает обратный отсчет, а третья цифра — возрастающая. Но второй параметр всегда равен нулю. Это нормально? - person Reza; 20.12.2016
comment
@VladimirBershov спасибо, что показали мне, как подключить сигнал ошибки, раньше я не мог его подключить. - person KernelPanic; 11.09.2019