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

简述

对于一个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()。
当然这个只能检查你是否有网络链接,而不能检测你是否连接到互联网。


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

  • 10
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: QtQTcpSocket类是Qt网络模块中的一个类,用于实现TCP网络通信。而内网穿透是一种技术,允许在两个不同的局域网之间建立直接的网络连接。 在Qt中,要实现内网穿透,可以使用QTcpServer和QTcpSocket配合使用。首先在服务器端使用QTcpServer监听指定的端口,等待客户端连接。然后在客户端中创建QTcpSocket对象,指定服务器的IP地址和端口号,通过connect函数与服务器建立连接。 为了实现内网穿透,通常需要借助第三方的工具或服务,如FRP、ngrok等。这些工具通过在公网上运行一个服务器,将公网IP和端口映射到内网中的指定IP和端口,从而实现内网穿透。在Qt应用程序中,可以通过配置这些工具来实现内网穿透。 具体操作步骤如下: 1. 在服务器端使用QTcpServer创建一个监听对象,并指定监听的IP地址和端口号。 2. 在客户端中创建一个QTcpSocket对象,并通过connect函数连接服务器的地址和端口号。 3. 在客户端中,通过connect信号和槽机制,监听连接成功和数据接收的信号,并在接收到数据时进行处理。 4. 在服务器端,通过QTcpServer的信号和槽机制,监听新连接信号,并在接收到新连接时创建一个新的QTcpSocket对象,并将其加入到连接列表中。 5. 通过配置内网穿透工具,将公网IP和端口映射到服务器的局域网IP和端口上。 6. 在远程机器上,通过指定公网IP和端口号来连接服务器,实现内网穿透。 总结: QtQTcpSocket类可以配合其他技术或工具实现内网穿透,通过监听和连接的方式,实现远程机器与内网服务器的通信。具体实现还需要借助第三方的工具或服务,如FRP、ngrok等来完成端口映射和数据传输。 ### 回答2: QT是一种跨平台的C++开发工具,而QTcpSocketQT网络模块中的一个类,用于在网络中进行TCP通信。内网穿透是一种将内部网络中的服务暴露给外部网络的技术。 在QT中实现内网穿透主要需要借助一些第三方库或服务,常用的有ngrok、frp等。这些工具可以将内部网络中的服务映射到外部网络上,使得可以通过外部网络访问到内部服务。 在使用QT开发中,可以通过QTcpSocket来实现与内网穿透工具之间的通信。首先,我们需要先启动内网穿透工具,将内部服务映射到外网,并获得外部访问地址。然后,在QT程序中使用QTcpSocket连接外部访问地址。 具体实现步骤如下: 1. 下载并安装一个内网穿透工具,如ngrok。 2. 在终端中运行ngrok启动命令,并指定内部服务的端口号,如"ngrok http 8080"。 3. ngrok生成一个外部访问地址,如"http://xxxx.ngrok.io"。 4. 在QT程序中创建一个QTcpSocket对象,使用其connectToHost方法连接到外部访问地址对应的IP地址和端口号。 5. 通过QTcpSocket对象进行数据通信,如发送和接收数据。 需要注意的是,由于内网穿透使用的是中间服务器进行数据转发,所以引入一定的延迟和性能损耗。此外,在实际应用中,还需要考虑网络安全性等因素。 总之,通过QTcpSocket和内网穿透工具的配合,可以实现在QT进行内网穿透,将内部服务暴露给外部网络进行访问。希望以上回答能对您有所帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值