Qt QTcpSocket 对连接服务器中断的不同情况进行判定

本文总结了C/S架构中客户端与服务器连接状态的六种常见断开情况,并分析了连接前后不同情况下的表现。此外,还介绍了通过心跳包、网络检测、Ping服务器等方法即时检测连接状态。

简述

对于一个C/S结构的程序,客户端有些时候需要实时得知与服务器的连接状态。而对于客户端与服务器断开连接的因素很多,现在就目前遇到的情况进行一下总结。

分为下面六种不同情况

  1. 客户端网线断开
  2. 客户端网络断开
  3. 客户端通过HTTP代理连接服务器,代理机器断开代理
  4. 客户端通过HTTP代理连接服务器,代理机器的网络断开
  5. 客户端通过HTTP代理连接服务器,代理机器的网线断开
  6. 服务器断开
同时对于以上六种情况又分为连接服务器之前和连接上服务器之后,下面就分别对不同的情况进行分析。

开始连接服务器之前

1、 客户端网线断开
此时用socket调用connectToHost方法连接服务器会立即触发QTcpSocket的error信号,我们可以绑定相应的槽去处理连接失败的结果。


2、 客户端网络断开
3、 客户端通过HTTP代理连接服务器,代理机器断开代理
4、 客户端通过HTTP代理连接服务器,代理机器的网络断开
5.、客户端通过HTTP代理连接服务器,代理机器的网线断开
6、 服务器断开
此时用socket调用connectToHost方法连接服务器并不会立即触发QTcpSocket的error信号,而是经过40s+的连接等待超时发出error信号,见下图。

这里写图片描述


已经连接上服务器

1、 客户端网线断开
此时socket不会发送error信号,也不会发送disconnect信号,查询资料是因为网线断开是属于物理链路层,tcp无法察觉到,socket仍处于连接状态。


2、 客户端网络断开
3、 客户端通过HTTP代理连接服务器,代理机器断开代理
4、 客户端通过HTTP代理连接服务器,代理机器的网络断开
5.、客户端通过HTTP代理连接服务器,代理机器的网线断开

第二和第三种情况下会立即触发error信号,而第四和第五种情况下会等待30s左右会发送error信号。


6、 服务器断开
此时socket会发送disconnect信号,可以绑定相应的槽去处理服务器断开的情况。

检测与服务器断开的另外方法

对于有些程序(客户端)需要立即知道与服务端连接状态,而不是等待几十秒之后才有信号通知到或者根本就检测不出与服务器断开,除了利用QTcpSocket提供的信号(有几种情况不会发出信号或发出信号延迟),这里列出另外几种处理方法。

1、发送心跳包,即客户端每隔一段时间发送一条报文,报文不需附带具体内容,只需要让服务端知道这是一条心跳报文,并回发一条消息,客户端收到这条消息后就得知与服务器保持连接的状态。

检测本地网络,定义一个时钟,每次timeout去检测本地的网络,关于怎么判断本地网络是否通畅呢?

2、可以用windows提供的IsNetworkAlive方法,返回为false为网络异常。加上头文件为#include “Sensapi.h”。同时需要包含Sensapi.lib。
(通过IsNetworkAlive方法判断本地网络,在客户端已经连接上服务器,并且禁用网络时会立即发送error信号,在error信号绑定的槽中去调用这个方法发现返回值为true,因为这种情况下禁用网络后会立即发送error信号,调用IsNetworkAlive方法时可能立即检测不到网络异常。如果通过断点的方式,在调用IsNetworkAlive时就会返回false)

    DWORD dwFlag;
    if (FALSE == IsNetworkAlive(&dwFlag))
    {
        qDebug() << "NetWorkError";
    }
注意:

但是这种方法,在本地存在虚拟机并且虚拟机开启时会失效,因为IsNetworkAlive会检测本地所有的网络,在网线断开后,可能检测到虚拟机网络正常,导致返回ture。

3、如果有自己的服务器就ping服务器(前提服务器不会挂),否则就ping一个相对可靠的IP (比如百度),通过看他ping的结果怎么样.
同时在C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址 这篇博客中用C++实现了 ping的 功能,有兴趣的小伙伴可以看一看,了解一下。

QProcess *cmd = new QProcess;
cmd->start("ping www.baidu.com");
// 等待ping 的结果
while (cmd->waitForFinished())
{
    QString result = QString::fromLocal8Bit(cmd->readAll());
    qDebug() << result;
}

QHostInfo::lookupHost("www.baidu.com", this, SLOT(lookedUp(QHostInfo)));

void lookedUp(QHostInfo &host)
{
     qDebug() << host.addresses().first().toString();
}
//得到IP 地址 就是在互联网上 如果不能得到 就不行

4、QNetworkConfigurationManager::isOnline()。
当然这个只能检查你是否有网络链接,而不能检测你是否连接到互联网。


对于需要自动重连的客户端可以通过以上方法,在判断出与服务器断开后可以重新连接,或者通过超时定时器进行重连,方法很多,在于尝试。

<think>我们正在处理一个关于Qt编程的问题,具体是如何设置QTcpSocket连接超时时间。根据提供的引用,我们可以总结出几种方法。 首先,引用[1]提供了一种方法:通过QNetworkConfiguration设置连接超时时间,并将其与QTcpSocket关联。具体步骤是: 1. 创建QNetworkConfigurationManager对象。 2. 获取默认配置。 3. 在配置上设置连接超时(以毫秒为单位)。 4. 创建一个QNetworkSession对象,使用该配置。 5. 将QNetworkSession对象设置为QTcpSocket的属性("_q_networksession")。 引用[4]提到了另一种方法:设置socket选项,但指出这种方法可能对连接超时效果有限,更多是在连接建立后起作用。它设置了LowDelayOption和KeepAliveOption。 另外,引用[5]提到了断开连接的处理,但这不是设置连接超时,而是处理连接断开的事件。 根据引用[1]和[4],我们推荐使用引用[1]的方法来设置连接超时时间,因为它是直接针对连接超时的设置。 因此,我们可以给出以下步骤: 1. 创建QTcpSocket对象。 2. 使用QNetworkConfigurationManager获取默认配置。 3. 设置配置的连接超时时间(例如3000毫秒)。 4. 创建QNetworkSession对象,传入配置。 5. 将QNetworkSession对象设置为socket的属性(使用键"_q_networksession")。 注意:在设置属性后,调用connectToHost()方法。如果连接超时,将会触发错误信号。 另外,我们也可以使用定时器来模拟超时,但这里我们按照引用[1]的方法。 代码示例: ```cpp #include <QTcpSocket> #include <QNetworkConfigurationManager> #include <QNetworkConfiguration> #include <QNetworkSession> #include <QSharedPointer> // ... QTcpSocket *socket = new QTcpSocket(this); // 创建配置管理器 QNetworkConfigurationManager manager; // 获取默认配置 QNetworkConfiguration config = manager.defaultConfiguration(); // 设置连接超时时间为3秒 config.setConnectTimeout(3000); // 创建网络会话 QSharedPointer<QNetworkSession> spNetworkSession(new QNetworkSession(config)); // 将网络会话设置为socket的属性 socket->setProperty("_q_networksession", QVariant::fromValue(spNetworkSession)); // 连接信号和槽,例如连接成功、错误等 connect(socket, &QTcpSocket::connected, this, &MyClass::onConnected); connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &MyClass::onError); // 连接服务器 socket->connectToHost("example.com", 1234); ``` 注意:上述方法中,我们使用了QSharedPointer来管理QNetworkSession对象,以避免内存泄漏。 另外,引用[4]提到的方法(设置socket选项)可以作为辅助手段,但可能不能直接设置连接超时。例如: ```cpp socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); ``` 但是,根据引用[4]的描述,这些选项对连接超时的影响有限。 因此,我们主要采用第一种方法。 同时,我们需要注意,连接超时后,会触发error信号,我们可以在这个信号的槽函数中处理超时错误(QAbstractSocket::SocketTimeoutError或QAbstractSocket::ConnectionRefusedError等)。 另外,引用[3]和[5]提到了断开连接的处理,我们可以参考设置断开连接信号处理,但这不是设置超时,而是处理断开。 综上所述,我们推荐使用配置网络会话的方法来设置连接超时。 现在,我们根据用户的问题,提供设置QTcpSocket连接超时的方法。</think>### QTcpSocket设置连接超时时间的方法 在Qt中设置QTcpSocket连接超时时间,主要有以下两种可靠方法: #### 方法1:使用QNetworkConfiguration(推荐) 这是官方推荐的方式,通过配置网络会话实现: ```cpp QTcpSocket* socket = new QTcpSocket; // 创建网络配置管理器 QNetworkConfigurationManager manager; QNetworkConfiguration config = manager.defaultConfiguration(); // 设置3秒超时(单位:毫秒) config.setConnectTimeout(3000); // 创建网络会话并绑定到socket QSharedPointer<QNetworkSession> spNetworkSession(new QNetworkSession(config)); socket->setProperty("_q_networksession", QVariant::fromValue(spNetworkSession)); // 连接服务器 socket->connectToHost("example.com", 1234); ``` **原理**:通过`QNetworkSession`管理底层网络连接,`setConnectTimeout()`直接设置TCP连接阶段的超时阈值[^1]。 #### 方法2:手动超时检测 当方法1不适用时,可用定时器实现: ```cpp QTcpSocket* socket = new QTcpSocket; QTimer* timeoutTimer = new QTimer(socket); // 设置3秒超时 timeoutTimer->setInterval(3000); timeoutTimer->setSingleShot(true); // 连接信号槽 QObject::connect(socket, &QTcpSocket::connected, [=](){ timeoutTimer->stop(); qDebug() << "连接成功"; }); QObject::connect(timeoutTimer, &QTimer::timeout, [=](){ socket->abort(); // 强制终止连接 qDebug() << "连接超时"; }); // 启动连接和定时器 socket->connectToHost("example.com", 1234); timeoutTimer->start(); ``` #### 注意事项: 1. **默认行为**:QTcpSocket没有内置连接超时设置,需手动实现[^2] 2. **错误处理**:连接失败会触发`errorOccurred`信号,可处理`QAbstractSocket::ConnectionRefusedError`等错误 3. **断开处理**:使用`disconnectFromHost()`和`close()`安全关闭连接[^3] 4. **选项限制**:`setSocketOption()`对连接超时效果有限[^4] #### 完整示例: ```cpp void connectWithTimeout(const QString &host, quint16 port) { QTcpSocket* socket = new QTcpSocket; // 方法1配置 QNetworkConfigurationManager mgr; QNetworkConfiguration cfg = mgr.defaultConfiguration(); cfg.setConnectTimeout(3000); // 3秒超时 QSharedPointer<QNetworkSession> session(new QNetworkSession(cfg)); socket->setProperty("_q_networksession", QVariant::fromValue(session)); // 连接信号 connect(socket, &QTcpSocket::connected, []{ qDebug() << "成功连接服务器"; }); connect(socket, &QTcpSocket::errorOccurred, [](QAbstractSocket::SocketError error){ if(error == QAbstractSocket::ConnectionRefusedError) qDebug() << "连接被拒绝"; else if(error == QAbstractSocket::SocketTimeoutError) qDebug() << "连接超时"; }); connect(socket, &QTcpSocket::disconnected, []{ qDebug() << "连接断开"; }); // [^5] socket->connectToHost(host, port); } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值