短线重连代码实现

客户端

复制代码
//断线重连客户端
#include <arpa/inet.h>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

using namespace std;

enum class Status {
  NEW,          //要去新建连接了
  CONNECTING,   //重新连接中
  CONNECTED,    //连接成功
  DISCONNECTED, //连接失败,需要重连
  CLOSED        //多次重连失败,关闭连接
};

class ClientConnect {
public:
  ClientConnect(const std::string &ip, int port, int count)
      : count_(count), ip_(ip), port_(port) {}
  ~ClientConnect() { disconnect(); }

  //建立连接
  void connect() {
    fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (fd_ < 0) {
      std::cout << "socket faild" << std::endl;
      exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port_);
    inet_pton(AF_INET, ip_.c_str(), &addr.sin_addr);
    int ret = ::connect(fd_, (sockaddr *)&addr, sizeof addr);
    if (ret < 0) {
      std::cout << "connect faild" << std::endl;
      disconnect();
      status_ = Status::DISCONNECTED;
      return;
    }
    status_ = Status::CONNECTED;
  }

  //查询当前状态
  Status status() { return status_; }

  //查询socketfd
  int fd() { return fd_; }

  //重连
  void reconnect() {
    status_ = Status::CONNECTING;
    for (int i = 0; i < count_; i++) {
      std::cout << "reconnecting... attempt " << i + 1 << std::endl;
      disconnect();
      connect(); // 调用类成员函数 connect()
      if (status_ == Status::CONNECTED) {
        return;
      }
      sleep(1); // 重连间隔
    }
    status_ = Status::CLOSED;
  }

  void disconnect() {
    if (fd_ != -1) {
      close(fd_);
      fd_ = -1;
    }
    status_ = Status::CLOSED;
  }

  void run() {
    //发送数据
    while (true) {
      std::string s;
      std::cout << "Please input:" << std::endl;
      if (!getline(std::cin, s)) {
        std::cout << "Input finished." << std::endl;
        status_ = Status::CLOSED;
        return;
      }
      if (s.empty()) {
        continue;
      }
      std::cout << "client say:" << s << std::endl;
      int ret = send(fd_, s.c_str(), s.size(), 0);
      if (ret < 0) {
        std::cout << "send error:" << strerror(errno) << std::endl;
        status_ = Status::DISCONNECTED;
        return;
      }
      //接收数据
      char buff[1024];
      int n = recv(fd_, buff, sizeof buff, 0);

      if (n > 0) {
        buff[n] = '\0';
        std::cout << "server say:" << buff << std::endl;
      } else if (n == 0) //连接断开
      {
        status_ = Status::DISCONNECTED;
        return;
      } else {
        std::cout << "error::" << strerror(errno) << endl;
        status_ = Status::CLOSED;
        return;
      }
    }
  }

private:
  Status status_ = Status::NEW;
  int fd_ = -1;
  int count_ = 0; //最大重试次数
  std::string ip_;
  int port_;
};

class TcpClient {
public:
  TcpClient(std::string ip, int port, int count) : cc(ip, port, count) {}
  ~TcpClient() {}
  void start() {
    while (true) {
      switch (cc.status()) {
      case Status::NEW:
        cc.connect();
        break;
      case Status::DISCONNECTED:
        cc.reconnect();
        break;
      case Status::CLOSED:
        cc.disconnect();
        cout << "连接已彻底关闭" << endl;
        return;
      case Status::CONNECTED:
        //发送数据
        cc.run();
        break;
      default:
        break;
      }
    }
  }

private:
  ClientConnect cc;
};

void Usage() { std::cout << "Usage:./client ip port" << std::endl; }

int main(int argc, char *argv[]) {
  if (argc != 3) {
    Usage();
    return 1;
  }
  std::string ip = argv[1];
  int port = std::stoi(argv[2]);
  TcpClient client(ip, port, 6);
  client.start();
}

服务端

复制代码
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <thread>
#include <vector>

void handle_client(int client_fd) {
    char buffer[1024];
    while (true) {
        memset(buffer, 0, sizeof(buffer));
        ssize_t n = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0) {
            std::string received(buffer);
            std::string response = "我收到你的消息:" + received;
            send(client_fd, response.c_str(), response.size(), 0);
            std::cout << "Received: " << received << " | Sent response." << std::endl;
        } else if (n == 0) {
            std::cout << "Client disconnected." << std::endl;
            break;
        } else {
            perror("recv");
            break;
        }
    }
    close(client_fd);
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " <port>" << std::endl;
        return 1;
    }

    int port = std::stoi(argv[1]);
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket");
        return 1;
    }

    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port);

    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        return 1;
    }

    if (listen(server_fd, 5) < 0) {
        perror("listen");
        return 1;
    }

    std::cout << "Echo Server started on port " << port << std::endl;

    while (true) {
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
        if (client_fd < 0) {
            perror("accept");
            continue;
        }

        std::cout << "New client connected: " << inet_ntoa(client_addr.sin_addr) << std::endl;
        std::thread(handle_client, client_fd).detach();
    }

    close(server_fd);
    return 0;
}

makefile

复制代码
CC = g++
CFLAGS = -Wall -g -pthread -std=c++11

all: server client

server: echo_server.cc
	$(CC) $(CFLAGS) echo_server.cc -o server

client: connect.cc
	$(CC) $(CFLAGS) connect.cc -o client

clean:
	rm -f server client

通过手动结束服务端模拟短线情况

相关推荐
D_evil__3 小时前
【Effective Modern C++】第三章 转向现代C++:16. 让const成员函数线程安全
c++
微风中的麦穗3 小时前
【MATLAB】MATLAB R2025a 详细下载安装图文指南:下一代科学计算与工程仿真平台
开发语言·matlab·开发工具·工程仿真·matlab r2025a·matlab r2025·科学计算与工程仿真
2601_949146534 小时前
C语言语音通知API示例代码:基于标准C的语音接口开发与底层调用实践
c语言·开发语言
开源技术4 小时前
Python Pillow 优化,打开和保存速度最快提高14倍
开发语言·python·pillow
学嵌入式的小杨同学4 小时前
从零打造 Linux 终端 MP3 播放器!用 C 语言实现音乐自由
linux·c语言·开发语言·前端·vscode·ci/cd·vim
syseptember4 小时前
Linux网络基础
linux·网络·arm开发
Queenie_Charlie5 小时前
前缀和的前缀和
数据结构·c++·树状数组
mftang5 小时前
Python 字符串拼接成字节详解
开发语言·python
jasligea6 小时前
构建个人智能助手
开发语言·python·自然语言处理
kokunka6 小时前
【源码+注释】纯C++小游戏开发之射击小球游戏
开发语言·c++·游戏