当前位置: 首页 > news >正文

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

🍑个人主页: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;        // 默认的sockfdclass 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]; // 接收bufferssize_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.mrgr.cn/news/42347.html

相关文章:

  • C++ 语言特性13 - 强枚举类型
  • 银河麒麟V10如何关闭定期锁屏功能?
  • C++网络编程之TCP协议
  • 0基础学习CSS(十六)尺寸和Display(显示) 与 Visibility(可见性)
  • 前缀和——从LeetCode题海中总结常见套路
  • Python 循环跳出模式
  • WarehouseController
  • CSS3--美开二度
  • 被字节恶心到了
  • 【分布式微服务云原生】深入探索Redis Cluster:打造高效、可扩展的数据集群
  • 《三体》中的“咒语”的 Python实现
  • 基于Springboot+Vue的饮食营养管理信息系统(含源码数据库)
  • Linux之实战命令25:xargs应用实例(五十九)
  • Linux编辑器Vim与Nano之全面比较
  • Java第二阶段---10方法带参---第三节 面向对象和面向过程的区别
  • C语言基础(7)之操作符(1)(详解)
  • LeetCode题练习与总结:丢失的数字--268
  • 习题5 循环
  • 如何让70B参数的大型语言模型在资源有限的边缘设备上高效运行?
  • C/S模型的简单实现(UDP服务器)、本地套接字(sockaddr_un )的讲解