QTcpSocket 保持活动选项不起作用

Posted

技术标签:

【中文标题】QTcpSocket 保持活动选项不起作用【英文标题】:QTcpSocket Keep alive option does not work 【发布时间】:2016-12-20 08:50:13 【问题描述】:

我有一个简单的程序作为我的客户端,它包含一个 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));

当我运行我的程序时,一切看起来都很好,并且将为我的套接字启用 keepalive 选项。但是当我在客户端拔下电缆时它不起作用。我把我的 netstat 输出带到下面,表明我的套接字启用了 keepalive 计时器。

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

我还在服务器端启用了keepalive选项,就像客户端一样。现在我有一些问题; 1-我什么时候应该启用keepalive选项?连接到服务器之后还是连接之前? 2-我应该写一些代码来捕捉我的程序中的keepalive错误吗?

顺便说一句,我的程序在 linux mint 17.1 中运行,我还将 sysctl.conf 和 proc/sys 中的 keepalive 选项更改为无效。

提前感谢您的帮助。 雷扎

【问题讨论】:

您发布的netstat 输出表明它确实有效。不清楚你在问什么。 How to detect internet disconnection on SSL/TCP sockets which were connected before?的可能重复 你有没有提到这个QAbstractSocket::disconnected () signal does not emit when switch is disconnected。作为替代方案,您也可以考虑使用各种waitfor...() 方法(即waitForReadyRead(milliseconds))。可以将超时设置为所需的量,然后在此期间还检查连接是否处于活动状态。顺便说一句,我是 Qt 的新手。您找到解决实际问题的方法了吗? @EJP,我认为 OP 有一个问题,即即使拔出互联网插头(如果我理解正确的话)插座也不会断开。 【参考方案1】:

最好使用Qt的函数setSocketOption:

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

枚举 QAbstractSocket::SocketOption

这个枚举表示可以在套接字上设置的选项。如果 需要,它们可以在收到 connected() 信号后设置 从套接字或在从 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:
        // ...
        // ...
    

【讨论】:

为什么会更好? @EJP,因为 Qt 有自己的功能,在这种情况下混合 Qt 和系统功能很奇怪。 Qt也是一个跨平台的框架 无关紧要。如果setsockopt() 没有返回-1,它显然已经工作了,那么这究竟是如何解决OP 的问题的呢? setsocket 返回 0 表示它是真的。我也尝试了 Qt 提供的 setSocketOption ,但它并没有解决我的问题。另外,如何使用此功能设置其他选项,例如空闲时间?它只启用keepalive选项。 @EJP 我想我的问题说得很清楚了。由于拔下网线,我的客户端套接字无法理解死连接。我可以在再次插入之前和之后捕获其他套接字错误。所以我几乎可以肯定我的代码是正确的。请看一下 netstat 输出 keepalive (0.16/0/0)。当我拔下电缆时,第一个数字开始倒计时,第三个数字开始倒计时。但第二个参数始终为零。没事吧?

以上是关于QTcpSocket 保持活动选项不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Twitter Bootstrap 选项卡活动类切换不起作用

ExtJs:在非活动选项卡中以编程方式选择 GridPanel 的行不起作用?

为啥我的 android 选项卡布局不起作用?

为啥在模式内部切换在 laravel 中不起作用?

使用UI-Bootstrap 0.11.0,角度js中的活动选项卡不起作用

颤动中的单选按钮活动颜色不起作用