客户端
//断线重连客户端
#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
通过手动结束服务端模拟短线情况
