实现TCP Connect的断线重连机制:策略与实践

news2024/10/5 5:33:13
🍑个人主页:Jupiter.
🚀 所属专栏:Linux从入门到进阶
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述


断线重连机制,它成为确保应用在网络不稳定情况下仍能持续提供服务的关键技术之一。本文旨在深入探讨TCP(传输控制协议)连接中的断线重连机制,解析其工作原理、设计原则、实现策略以及在实际应用中的挑战与解决方案。试着写一个客户端重连的代码,模拟并理解一些客户端行为,比如游戏客户端等。

断线重连代码

#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

enum Status
{
    NEW,          // 新建状态,就是单纯的连接
    CONNECTING,   // 正在连接,仅仅方便查询 conn 状态
    CONNECTED,    // 连接或者重连成功
    DISCONNECTED, // 重连失败
    CLOSED        // 连接失败,经历重连,无法连接
};

const static int defaultretryinterval = 1;  // 重试时间间隔
const static int defaultmaxretries = 5;     // 最大重试次数
const static int defaultsockfd = -1;        // 默认的sockfd

class ConnectClient
{
public:
    ConnectClient(std::string &serverip, uint16_t serverport)   
        : _serverip(serverip),
          _serverport(serverport),
          _sockfd(defaultsockfd),
          _retry_interval(defaultretryinterval),
          _max_retries(defaultmaxretries),
          _status(Status::NEW)
    {
    }
    void Connect() // 建立连接
    {
        // 创建 流式socket
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            std::cout << "socket create fail..." << std::endl;
            exit(2);
        }

        // 连接
        struct sockaddr_in serveraddr;
        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = _serverport;
        serveraddr.sin_addr.s_addr = inet_addr(_serverip.c_str());

        int n = connect(_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
        if (n < 0) // 连接失败
        {
            Disconnect(); // 重置_sockfd
            _status = Status::DISCONNECTED;
            return;
        }
        // 连接成功
        _status = Status::CONNECTED;
        std::cout << "connect success..." << std::endl;
    }
    void Reconnect() // 重新连接
    {
        _status = Status::CONNECTING;
        int cnt = 1;
        while (true)
        {
            Connect();
            if (_status == Status::CONNECTED)
            {
                return;
            }
            std::cout << "重连次数: " << cnt << ", 最大上限: " << _max_retries << std::endl;
            cnt++;
            if (cnt > _max_retries)   //超过连接设置的最大次数,直接连接失败,关闭client
            {
                _status = Status::CLOSED;
                return;
            }
            sleep(defaultretryinterval);
        }
    }

    void process()  //客服端连接成功执行的业务
    {
        while (true)
        {
            std::string str = "Hello world!";
            ssize_t n = ::send(_sockfd, str.c_str(), str.size(), 0);
            if (n > 0) // 发送成功
            {
                char buffer[1024]; // 接收buffer
                ssize_t m = ::recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
                if (m > 0) // 接收成功
                {
                    buffer[m] = 0;
                    std::cout << "server echo#" << buffer << std::endl;
                }
                else // 接收失败
                {
                    _status = Status::DISCONNECTED; // 接受失败,说明连接断开了 ,设置状态,重新连接
                    break;
                }
            }
            else // 发送失败
            {
                _status = Status::CLOSED; // 连接成功,但是发送失败,说明服务器异常,直接将Client关闭
                break;
            }
        }
    }
    void Disconnect()   //关闭Client
    {
        if (_sockfd > defaultsockfd)
        {
            ::close(_sockfd);
            _status = Status::CLOSED;
            _sockfd = defaultsockfd;
        }
    }

    Status GetStatus() // 获取当前状态
    {
        return _status;
    }

    ~ConnectClient()
    {
    }

private:
    int _sockfd;
    uint16_t _serverport;     // server port 端口号
    std::string _serverip;    // server ip 地址
    int _retry_interval;      // 重试时间间隔
    int _max_retries;         // 重试次数
    Status _status;           // 连接状态
};

class TcpClinet
{
public:
    TcpClinet(std::string &serverip, uint16_t serverport)
        : _connect(serverip, serverport)
    {
    }
    void Excute()     // 执行client
    {
        while (true)
        {
            switch (_connect.GetStatus())
            {
            case Status::NEW:          //如果状态是新创建,则连接
                _connect.Connect();
                break;
            case Status::CONNECTED:    //已经建立连接了
                _connect.process();    //进行通信
                break;
            case Status::DISCONNECTED:  //断开连接了
                _connect.Reconnect();   //进行重连
                break;
            case Status::CLOSED:        //关闭
                _connect.Disconnect();  //则关闭文件描述符
                return;
            default:
                break;
            }
        }
    }
    ~TcpClinet()
    {
    }

private:
    ConnectClient _connect;
};

void Usage(std::string args)
{
    std::cout << "Usage:\n\t" << args << " serverip serverport" << std::endl;
}
// ./Tcp_Client serverip serverport
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    std::string serverip = argv[1];
    int serverport = std::stoi(argv[2]);

    std::shared_ptr<TcpClinet> TcpClientptr = std::make_shared<TcpClinet>(serverip, serverport);
    TcpClientptr->Excute();

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2189354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅聊前后端分离开发和前后端不分离开发模式

1.先聊聊Web开发的开发框架Spring MVC 首先要知道&#xff0c;Spring MVC是Web开发领域的一个知名框架&#xff0c;可以开发基于请求-响应模式的Web应用。而Web开发的本质是遵循HTTP&#xff08;Hyper Text Transfer Protocol: 超文本传输协议&#xff09;协议【发请求&#xf…

仿RabbitMQ实现消息队列客户端

文章目录 客⼾端模块实现订阅者模块信道管理模块异步⼯作线程实现连接管理模块生产者客户端消费者客户端 客⼾端模块实现 在RabbitMQ中&#xff0c;提供服务的是信道&#xff0c;因此在客⼾端的实现中&#xff0c;弱化了Client客⼾端的概念&#xff0c;也就是说在RabbitMQ中并…

V2M2引擎源码BlueCodePXL源码完整版

V2M2引擎源码BlueCodePXL源码完整版 链接: https://pan.baidu.com/s/1ifcTHAxcbD2CyY7gDWRVzQ?pwdmt4g 提取码: mt4g 参考资料&#xff1a;BlueCodePXL源码完整版_1234FCOM专注游戏工具及源码例子分享

图解大模型计算加速系列:vLLM源码解析3,块管理器(BlockManager)上篇

vllm块管理器又分成朴素块管理器&#xff08;UncachedBlockAllocator&#xff09;和prefix caching型块管理器&#xff08;CachedBlockAllocator&#xff09;。本篇我们先讲比较简单的前者&#xff0c;下篇我们来细看更有趣也是更难的后者。 【全文目录如下】 【1】前情提要…

阿里巴巴开源的FastJson 1反序列化漏洞复现攻击保姆级教程

免责申明 本文仅是用于学习检测自己搭建的靶场环境有关FastJson1反序列化漏洞的原理和攻击实验,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》‌及其所在…

Linux高级编程_29_信号

文章目录 进程间通讯 - 信号信号完整的信号周期信号的编号信号的产生发送信号1 kill 函数(他杀)作用&#xff1a;语法&#xff1a;示例&#xff1a; 2 raise函数(自杀)作用&#xff1a;示例&#xff1a; 3 abort函数(自杀)作用&#xff1a;语法&#xff1a;示例&#xff1a; 4 …

macos安装git并连接gitCode远程仓库

文章目录 资料地址下载和安装初始化配置本地全局配置&#xff0c;SSH公私密钥生成远程SSH key配置 新建代码仓库&#xff0c;并关联到本地 资料地址 git官网地址gitCode地址 下载和安装 打开git官网地址&#xff0c;直接下载。【不建议使用brew&#xff0c;因为本人实践&…

【Qt】控件概述(2)—— 按钮类控件

控件概述&#xff08;2&#xff09; 1. PushButton2. RadioButton——单选按钮2.1 使用2.2 区分信号 clicked&#xff0c;clicked(bool)&#xff0c;pressed&#xff0c;released&#xff0c;toggled(bool)2.3 QButtonGroup分组 3. CheckBox——复选按钮 1. PushButton QPushB…

B树系列解析

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

etcd 快速入门

简介 随着go与kubernetes的大热&#xff0c;etcd作为一个基于go编写的分布式键值存储&#xff0c;逐渐为开发者所熟知&#xff0c;尤其是其还作为kubernetes的数据存储仓库&#xff0c;更是引起广泛专注。 本文我们就来聊一聊etcd到底是什么及其工作机制。 首先&#xff0c;…

查找回收站里隐藏的文件

在Windows里&#xff0c;每个磁盘分区都有一个隐藏的回收站Recycle&#xff0c; 回收站里保存着用户删除的文件、图片、视频等数据&#xff0c;比如&#xff0c;C盘的回收站为C:\RECYCLE.BIN\&#xff0c;D盘的的回收站为D:\RECYCLE.BIN\&#xff0c;E盘的的回收站为E:\RECYCLE…

【解决方案】JVM调优:给定资源条件下减少Full GC频率

1 缘起 在一次其他团队技术分享时,有幸进行了旁听, 谈到一个应用场景,服务端在给定的资源下,频繁Full GC, 降低了服务请求处理能力以及任务处理能力,频繁Full GC,导致服务处理能力下降, 服务在Full GC期间无法处理用户请求以及其他任务,服务不稳定,可以理解为服务在…

【C++算法】9.双指针_四数之和

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 18.四数之和 题目描述&#xff1a; 解法 解法一&#xff1a;排序暴力枚举利用set去重 解法二&#xff1a;排序双指针 从左往右依次固定一个数a在a后面的区间里&#x…

坐标系变换总结

二维情况下的转换 1 缩放变换 形象理解就是图像在x方向和y方向上放大或者缩小。 代数形式&#xff1a; { x ′ k x x y ′ k y y \begin{cases} x k_x x \\ y k_y y \end{cases} {x′kx​xy′ky​y​ 矩阵形式&#xff1a; ( x ′ y ′ ) ( k x 0 0 k y ) ( x y ) \be…

【C语言】数据在内存中的存储(万字解析)

文章目录 一、大小端字节序和字节序判断1.案例引入2.什么是大小端字节序3.大小端字节序判断 二、整数在内存中的存储以及相关练习1.整型在内存中的存储2.练习练习1&#xff1a;练习2练习3练习4练习5&#xff1a;练习6 三、浮点数在内存中的存储1.案例引入2.浮点数在内存中的存储…

uniapp+Android面向网络学习的时间管理工具软件 微信小程序

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 用户功能…

KVM虚拟化技术介绍

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 虚拟化技术是云计算的基础&#xff0c;什么是虚拟化&#xff1f;虚拟化技术的本质是什么&#xff1f;主流的虚拟化技术有哪些&#xff1f;本章将为您揭晓 一.虚拟化概述 虚拟化是一种将计…

【有啥问啥】领域自适应(Domain Adaptation, DA)详解

领域自适应&#xff08;Domain Adaptation, DA&#xff09;详解 引言 在机器学习和深度学习的广泛应用中&#xff0c;一个核心挑战在于模型往往在一个特定数据集&#xff08;源领域&#xff09;上训练后&#xff0c;难以直接应用于另一个不同但相关的数据集&#xff08;目标领…

通信工程学习:什么是ICMP因特网控制报文协议

ICMP&#xff1a;因特网控制报文协议 ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制报文协议&#xff09;是TCP/IP协议簇中的一个重要子协议&#xff0c;主要用于在IP主机和路由器之间传递控制消息。以下是关于ICMP协议的详细解释&#xff1a; 一…

Pikachu-Unsafe FileUpload-客户端check

上传图片&#xff0c;点击查看页面的源码&#xff0c; 可以看到页面的文件名校验是放在前端的&#xff1b;而且也没有发起网络请求&#xff1b; 所以&#xff0c;可以通过直接修改前端代码&#xff0c;删除 checkFileExt(this.value) 这部分&#xff1b; 又或者先把文件名改成…