C++ Qt TCP的心跳检测机制,断线重连技术,应用层代码重新实现

这篇具有很好参考价值的文章主要介绍了C++ Qt TCP的心跳检测机制,断线重连技术,应用层代码重新实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言:

一、Qt直接启动本身的KeepAlive

二、在应用层自己实现一个心跳检测

 三、自定义心跳代码实现:

完整客户端服务端工程下载:

共用的结构体相关头文件:

        客户端部分核心代码:

        服务端部分核心代码:

运行结果展示:


前两篇关于qt tcp 相关的,可以通过以下传送门查看:

Qt TCP相关的一些整理:客户端常见操作 socket 通信 network-CSDN博客

Qt TCP相关的一些整理:服务端常见操作 socket 通信 network-CSDN博客

前言:

        TCP本身是有一个保活状态的 keep-alive机制,默认是关闭的,需要单独启动就可以;默认保活时间是2小时,不过这个机制是在协议层,也就是传输层生效的,如果应用层出问题了,就不能及时发现问题;如果想要实现断线重连的操作,这个就不好实现了。

        另一种方式,可以在应用层自定义模拟这个心跳检测机制,使用线程或者定时器来定时发心跳包即可实现保活功能,并且能做到断线重连的操作。

一、Qt直接启动本身的KeepAlive

    m_client = new QTcpSocket(this);
    // 启动心跳检测
    m_client->setSocketOption(QAbstractSocket::KeepAliveOption,true);
    m_client->connectToHost("127.0.0.1",8898);

二、在应用层自己实现一个心跳检测

        客户端部分:需要使用定时器来定时发送心跳包,并且根据间隔和保活总时长来设定一个阈值次数,一开始按最大时长的次数来初始化,当不停的递减阈值为0时,就需要断线,如果需要重连,那就重新连接一下;当然收到包时,需要重置阈值;

        服务端部分:需要使用一个map容器来保存已经连上的套接字及阈值,起一条线程来定时轮询容器,当发现阈值为0时则断线,并且从容器中删除键值对;当新的客户端连接成功连上时,要增加新的键值对到map容器中;当收到数据包时,要对阈值进行重置;

 三、自定义心跳代码实现:

完整客户端服务端工程下载:

点我下载

共用的结构体相关头文件:

struct_data.h 源码
#ifndef STRUCT_DATA_H
#define STRUCT_DATA_H

enum TypeInfo{
    HEART_CHECK_REQ,   // 心跳检测请求
    HEART_CHECK_RES,   // 心跳检测响应
};

struct Head
{
    int type;
    int len;
};

struct HeartCheckReq
{
    Head head;
    HeartCheckReq() {
        head.type = HEART_CHECK_REQ;
        head.len = sizeof(HeartCheckReq);
    }
};

struct HeartCheckRes
{
    Head head;
    HeartCheckRes() {
        head.type = HEART_CHECK_RES;
        head.len = sizeof(HeartCheckRes);
    }
};

#endif // STRUCT_DATA_H

        客户端部分核心代码:

头文件代码: 

#ifndef TCPMAINWINDOW_H
#define TCPMAINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QTimer>
#include <QTime>
#include "struct_data.h"

namespace Ui {
class TcpMainWindow;
}

class TcpMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit TcpMainWindow(QWidget *parent = 0);
    ~TcpMainWindow();

private slots:
    void myRead();  // 收包槽函数

    void on_pushButton_clicked();

    void heartCheckSlot(); // 定时发心跳包的槽

private:
    Ui::TcpMainWindow *ui;
    QTcpSocket *m_client;
    int m_heartCheckTimes;
    QTimer *m_checkTimer;

};

#endif // TCPMAINWINDOW_H

源文件代码:

#include "tcpmainwindow.h"
#include "ui_tcpmainwindow.h"
#include <QDebug>

#define HEART_CHECK_TIMES 6 // 保活30秒,每5秒发一次心跳包,阈值为6

TcpMainWindow::TcpMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::TcpMainWindow)
{
    ui->setupUi(this);
    m_client = new QTcpSocket(this);
    // 启动tcp默认的保活
    //m_client->setSocketOption(QAbstractSocket::KeepAliveOption,true);
    m_client->connectToHost("127.0.0.1",8898);
    if(m_client->waitForConnected()){
        qDebug()<<"conn ok";
        connect(m_client,SIGNAL(readyRead()),this,SLOT(myRead()));
        m_heartCheckTimes = HEART_CHECK_TIMES; // 阈值初始化
        // 心跳检测相关的定时器 和 关联操作
        m_checkTimer = new QTimer(this);
        connect(m_checkTimer,SIGNAL(timeout()),this,SLOT(heartCheckSlot()));
        m_checkTimer->start(5000); // 5秒的间隔定时

    }else{
        qDebug()<<"conn fail"<<m_client->errorString();
    }
}

TcpMainWindow::~TcpMainWindow()
{
    delete ui;
}

void TcpMainWindow::myRead()
{
    QByteArray buffer = m_client->readAll();
    qDebug()<<buffer;
    // 只是简单的打印输出,还没有做解包处理

    m_heartCheckTimes = HEART_CHECK_TIMES;
}

void TcpMainWindow::on_pushButton_clicked()
{
    char buffer[] = "码蚁软件欢迎您";
    qDebug()<<m_client->write(buffer,sizeof(buffer));
}

void TcpMainWindow::heartCheckSlot()
{
    HeartCheckReq req;
    m_client->write((char*)&req,req.head.len); // 发送心跳包
    m_heartCheckTimes--; // 递减阈值
    ui->textBrowser->append(QString("当前时间:%1 心跳阈值为 %2").arg(QTime::currentTime().toString()).arg(m_heartCheckTimes));
    if(m_heartCheckTimes <= 0){
        // 需要做断线重连操作
        m_client->close();
        m_client->connectToHost("127.0.0.1",8898);
        if(m_client->waitForConnected()){
            m_heartCheckTimes = HEART_CHECK_TIMES; // 重连成功,重置阈值
            ui->textBrowser->append("重连成功");
        }
    }
}

        服务端部分核心代码:

头文件代码: 

#ifndef SERVERMAINWINDOW_H
#define SERVERMAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
#include "struct_data.h"

namespace Ui {
class ServerMainWindow;
}

class ServerMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit ServerMainWindow(QWidget *parent = 0);
    ~ServerMainWindow();
private slots:
    void connectSlot(); // 处理连接的槽
    void clientSlot(); // 与客户端交互的槽
    void checkTimer(); // 定时检测心跳的槽
private:
    Ui::ServerMainWindow *ui;
    QTcpServer *m_server;
    QMap<QTcpSocket*,int> m_clients;
    QTimer *m_checkTimer;
};

#endif // SERVERMAINWINDOW_H

源文件代码:

#include "servermainwindow.h"
#include "ui_servermainwindow.h"
#include <QDebug>

#define HEART_CHECK_TIMES 6

ServerMainWindow::ServerMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ServerMainWindow)
{
    ui->setupUi(this);
    m_server = new QTcpServer(this);

    if(m_server->listen(QHostAddress::Any,8898)){
        qDebug()<<"listen ok";
        connect(m_server,SIGNAL(newConnection()),this,SLOT(connectSlot()));
        // 心跳检测相关的定时器及关联操作
        m_checkTimer = new QTimer(this);
        connect(m_checkTimer,SIGNAL(timeout()),this,SLOT(checkTimer()));
        m_checkTimer->start(5000);

    }else{
        qDebug()<<"listen fail"<<m_server->errorString();
    }

}

ServerMainWindow::~ServerMainWindow()
{
    delete ui;
}

void ServerMainWindow::connectSlot()
{
    QTcpSocket *client = m_server->nextPendingConnection();
    client->setSocketOption(QAbstractSocket::KeepAliveOption,true);
    qDebug()<<client;
    if(!client->isValid()) return;
    m_clients[client] = HEART_CHECK_TIMES; // 用于心跳检测的map
    // 关联与客户端通信的自定义收包槽
    connect(client,SIGNAL(readyRead()),this,SLOT(clientSlot()));
    QByteArray buffer = "欢迎来到码蚁软件服务器。";
    qDebug()<<client->write(buffer);
}

void ServerMainWindow::clientSlot()
{
    QTcpSocket * client = static_cast<QTcpSocket *>(sender());
    QByteArray buffer = client->readAll();
    qDebug()<<buffer.data();
    m_clients[client] = HEART_CHECK_TIMES; // 重置心跳阈值
    int type = ((Head*)buffer.data())->type;
    if(type == HEART_CHECK_REQ){
        ui->textBrowser->append(QString("收到 %1 端口 %2 心跳包").arg(client->peerAddress().toString()).arg(client->peerPort()));
        // 回一个响应包
        HeartCheckRes res;
        client->write((char*)&res,res.head.len);
    }
}

void ServerMainWindow::checkTimer()
{
    for(auto it=m_clients.begin();it!=m_clients.end();){
        it.value()--;
        ui->textBrowser->append(QString("%1 %2 的阈值 %3").arg(it.key()->peerAddress().toString()).arg(it.key()->peerPort()).arg(it.value()));
        if(it.value()==0){
            ui->textBrowser->append(QString("发现无用连接 %1").arg(it.key()->peerAddress().toString()));
            it.key()->close();
            m_clients.erase(it++);
        }else{
            it++;
        }
    }
}

运行结果展示:

qt tcp 心跳,Qt,tcp/ip,网络,服务器,c++,qt,算法,开发语言

当关闭服务端之后,再重新开启服务端:

qt tcp 心跳,Qt,tcp/ip,网络,服务器,c++,qt,算法,开发语言文章来源地址https://www.toymoban.com/news/detail-751625.html

到了这里,关于C++ Qt TCP的心跳检测机制,断线重连技术,应用层代码重新实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • websocket断线重连&&心跳检测

    封装websocket 实现断线重连跟心态检测,使用的typeScript去封装 在nodejs 安装ws库 代码如下(示例):  服务端实现ws 创建一个server.js 文件 运行ws服务   node .server.js  客户端实现websocket 创建一个socket.ts 文件 vue 页面使用 断开ws服务 断线  启动服务后 自动重连

    2024年01月19日
    浏览(39)
  • uniapp使用WebSocket断线,心跳重连机制

    提示:我们在使用WebSocket,经常会遇到有的时候给别人发消息,别人会接收不到,这个时候就有可能是WebSocket断线了,所以这个时候心跳包就出现了 提示:可直接使用,记得把对应地址替换一下

    2024年04月12日
    浏览(43)
  • websocket实时通讯和socket.io实时通信库的使用;心跳机制与断线重连

    https://zh.javascript.info/websocket WebSocket 是一种网络通信协议,就类似于 HTTP 也是一种通信协议。 为什么需要 WebSocket? 因为 HTTP 协议有一个缺陷:通信只能由客户端发起。 代码解析: 创建WebSocket实例:通过 new WebSocket() 创建一个WebSocket实例。在括号中传入服务器的URL,该URL指定了

    2024年02月16日
    浏览(42)
  • WebSocket心跳检测和重连机制

    心跳和重连的目的用一句话概括就是客户端和服务端保证彼此还活着,避免丢包发生。 websocket 连接断开有以下两证情况: 前端断开 在使用 websocket 过程中,可能会出现网络断开的情况,比如信号不好,或者网络临时关闭,这时候websocket的连接已经断开,而不同浏览器有不同

    2024年01月21日
    浏览(41)
  • C++ TCP/IP 关于tcp断线重连的问题

    在工控上经常用到tcp连接,比如串口服务器或某些支持modbustcp协议的仪表等,以前尽量使用串口服务器的虚拟串口功能,现在逐步使用上了tcpserver或tcpclient模式。 搜索了个C++ 的tcp断线重连的案例(http://www.cnblogs.com/kingdom_0/articles/2571727.html),使用这个的原因还因其使用的是

    2024年02月10日
    浏览(30)
  • SpringBoot+Netty实现TCP客户端实现接收数据按照16进制解析并存储到Mysql以及Netty断线重连检测与自动重连

    在SpringBoot项目中需要对接三方系统,对接协议是TCP,需实现一个TCP客户端接收 服务端发送的数据并按照16进制进行解析数据,然后对数据进行过滤,将指定类型的数据 通过mybatis存储进mysql数据库中。并且当tcp服务端断连时,tcp客户端能定时检测并发起重连。 全流程效果  

    2024年02月03日
    浏览(38)
  • uniapp websocket机制 心跳 重连

    在开发程序过程中通信功能还是比较常用到的,本文主要介绍的是uniapp中websocket的使用 websocket建立连接后,断开、心跳机制重新链接的一个过程。 关于uni.connectSocket可仔细阅读uniapp官网中的uni.connetSocket以及连接socket创建的实例 SocketTask   具体代码如下:内有代码详细注解,

    2024年02月12日
    浏览(40)
  • java实现WebSocket客户端&&断线重连机制

    1、引入maven依赖(注意版本) 2、代码

    2024年02月16日
    浏览(49)
  • Flutter:WebSocket封装-实现心跳、重连机制

    前言Permalink Flutter简介 Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展。同时 Flutter还使用 Nat

    2024年02月10日
    浏览(53)
  • TCP通讯(三次握手、四次挥手;滑动窗口;TCP状态转换;端口复用;TCP心跳检测机制)

     前言:建议看着图片,根据文字描述走一遍TCP通讯过程,加深理解。 目录 TCP通信时序: 1)建立连接(三次握手)的过程: 2)数据传输的过程: 3)关闭连接(四次挥手)的过程: 滑动窗口 (TCP流量控制): TCP状态转换: 半关闭: 2MSL: 程序设计中的问题: 端口复用:

    2024年02月03日
    浏览(89)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包