有问题请指出,谢谢
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <chrono>
#include <thread>
#include <fcntl.h>
int sock = -1; // 全局变量套接字
const int kMaxRetryCount = 60; // 最大重试次数
const int kReconnectInterval = 1; // 重连间隔时间(秒)
const int kConnectTimeout = 2; // 连接等待时间(秒)
#define TCP_SERVER_IP "192.168.8.115"
#define TCP_SERVER_PORT 60000
#define RECV_TIMER 500 //(MS)
#define SEND_TIMER 1000 //(MS)
void handleSignal(int signum)
{
if (signum == SIGPIPE)
{
std::cerr << "Broken Pipe signal received" << std::endl;
}
}
// 连接服务器
bool connectToServer(const std::string &ip, int port)
{
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1)
{
std::cerr << "Failed to create socket: " << strerror(errno) << std::endl;
return false;
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());
// 非阻塞模式连接服务端
int flags = fcntl(sock, F_GETFL, 0); // 获取套接字当前的文件状态标志(file status flags)
fcntl(sock, F_SETFL, flags | O_NONBLOCK); // 设置套接字为非阻塞模式
int connect_result = connect(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
if (connect_result == -1 && errno == EINPROGRESS) // 临时错误:如果连接正在进行,则继续等待
{
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(sock, &write_fds);
struct timeval timeout
{
};
timeout.tv_sec = kConnectTimeout; // 连接等待时间
connect_result = select(sock + 1, NULL, &write_fds, NULL, &timeout);
if (connect_result > 0 && FD_ISSET(sock, &write_fds)) // 可写:说明连接完成,可切换回阻塞模式
{
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
}
else if (connect_result == 0)
{
// 超时:关闭套接字,并处理超时情况
std::cerr << "connect to server timeout: " << strerror(errno) << std::endl;
close(sock);
return false;
}
else
{
// 出错:关闭套接字,并处理错误情况
std::cerr << "Failed to connect to server: " << strerror(errno) << std::endl;
close(sock);
return false;
}
}
else if (connect_result == -1)
{
// 错误:关闭套接字,并处理错误情况
std::cerr << "Failed to connect to server: " << strerror(errno) << std::endl;
close(sock);
return false;
}
else
{
// 连接已完成,可切换回阻塞模式
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
}
signal(SIGPIPE, handleSignal);
std::cout << "Connected to server" << std::endl;
return true;
}
// 断线重连
bool reconnectToServer(const std::string &ip, int port)
{
for (int retryCount = 0; retryCount < kMaxRetryCount; ++retryCount)//每次重连计数
{
std::cerr << "Attempt #" << retryCount + 1 << " to connect to server..." << std::endl;
if (connectToServer(ip, port))
{
return true;
}
std::cerr << "Failed to connect to server, retrying in " << kReconnectInterval << " seconds..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(kReconnectInterval));//重连间隔时间
}
std::cerr << "Failed to connect to server after " << kMaxRetryCount << " retries" << std::endl;
return false;
}
// 发送数据
bool sendData(const char *message)
{
ssize_t sendSize = send(sock, message, strlen(message), 0); // 非阻塞I/O操作send()
if (sendSize < 0)
{
std::cerr << "Failed to send message to server: " << strerror(errno) << std::endl;
return false;
}
else if (sendSize < strlen(message))
{
std::cerr << "Incomplete message sent to server" << std::endl;
return false;
}
std::cout << "Sent message to server: " << message << std::endl;
return true;
}
// 接收数据
bool receiveData()
{
char buffer[1024] = {0};
ssize_t recvSize = recv(sock, buffer, sizeof(buffer) - 1, MSG_DONTWAIT); // 非阻塞I/O操作recv()
if (recvSize < 0)
{
// 如果send()返回-1并且errno等于EWOULDBLOCK或EAGAIN,则说明非阻塞I/O操作仍在进行
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
std::cerr << "Failed to receive message from server: " << strerror(errno) << std::endl;
return false;
}
}
else if (recvSize == 0)
{
std::cerr << "Server closed connection" << std::endl;
return false;
}
buffer[recvSize] = '\0';
std::cout << "Received Size: " << (int)recvSize << std::endl;
return true;
}
int main(int argc, char *argv[])
{
std::string ip = TCP_SERVER_IP;
int port = TCP_SERVER_PORT;
// 连接服务器
if (!connectToServer(ip, port))
{
if (!reconnectToServer(ip, port))
{
std::cerr << "Terminating program..." << std::endl;
return -1;
}
}
// 定义发送和接收数据的消息
const char *sendMsg = "Hello, server!";
const char *recvMsg = "Server, hello!";
// 定时器
std::chrono::time_point<std::chrono::steady_clock> time_recv_start = std::chrono::steady_clock::now(); // 记录开始时间
std::chrono::time_point<std::chrono::steady_clock> time_send_start = std::chrono::steady_clock::now(); // 记录开始时间
std::chrono::time_point<std::chrono::steady_clock> current_time = time_send_start;// 记录当前时间
long long time_recv_duration, time_send_duration;
while (true)
{
current_time = std::chrono::steady_clock::now(); // 记录当前时间
time_recv_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - time_recv_start).count(); // 计算经过的时间
if (time_recv_duration >= RECV_TIMER)
{
time_recv_start = std::chrono::steady_clock::now(); // 记录开始时间
// 接收数据
if (!receiveData())
{
close(sock);
std::cerr << "Failed to communicate with server, reconnecting..." << std::endl;
if (!reconnectToServer(ip, port))
{
std::cerr << "Terminating program..." << std::endl;
return -1;
}
}
}
current_time = std::chrono::steady_clock::now(); // 记录当前时间
time_send_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - time_send_start).count(); // 计算经过的时间
if (time_send_duration >= SEND_TIMER) // 如果经过的时间大于等于100ms
{
time_send_start = std::chrono::steady_clock::now(); // 记录开始时间
// 发送数据
if (!sendData(sendMsg))
{
close(sock);
std::cerr << "Failed to communicate with server, reconnecting..." << std::endl;
if (!reconnectToServer(ip, port))
{
std::cerr << "Terminating program..." << std::endl;
return -1;
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));//1ms
}
return 0;
}