149 lines
3.8 KiB
C++
149 lines
3.8 KiB
C++
#include "server_heartbeat.h"
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include "spdlog/spdlog.h"
|
|
|
|
namespace Heartbeat {
|
|
|
|
// 配置常量实现
|
|
const int PORT = 8888;
|
|
const int TIMEOUT = 15;
|
|
const int HEARTBEAT_INTERVAL = 10;
|
|
|
|
// 全局变量
|
|
std::vector<int> clients;
|
|
std::mutex clients_mutex;
|
|
|
|
// 主函数实现
|
|
void start_server() {
|
|
int server_sock = -1;
|
|
sockaddr_in server_addr = {};
|
|
|
|
if (!initialize_socket(server_sock)) {
|
|
return;
|
|
}
|
|
|
|
bind_socket(server_sock, server_addr);
|
|
listen_for_connections(server_sock);
|
|
accept_connections(server_sock);
|
|
|
|
close(server_sock);
|
|
}
|
|
|
|
bool initialize_socket(int& server_sock) {
|
|
server_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (server_sock < 0) {
|
|
perror("Socket creation failed");
|
|
return false;
|
|
}
|
|
|
|
int opt = 1;
|
|
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
|
|
perror("Setsockopt failed");
|
|
close(server_sock);
|
|
return false;
|
|
}
|
|
spdlog::info("Heartbeat program started.");
|
|
return true;
|
|
}
|
|
|
|
void bind_socket(int server_sock, sockaddr_in& 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_sock, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
|
perror("Bind failed");
|
|
close(server_sock);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void listen_for_connections(int server_sock) {
|
|
if (listen(server_sock, 5) < 0) {
|
|
perror("Listen failed");
|
|
close(server_sock);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
std::cout << "Server started on port " << PORT << std::endl;
|
|
}
|
|
|
|
void accept_connections(int server_sock) {
|
|
while (true) {
|
|
sockaddr_in client_addr;
|
|
socklen_t client_len = sizeof(client_addr);
|
|
int client_sock = accept(server_sock, (sockaddr*)&client_addr, &client_len);
|
|
|
|
if (client_sock < 0) {
|
|
perror("Accept failed");
|
|
continue;
|
|
}
|
|
|
|
std::cout << "[+] New client connected: " << client_sock << std::endl;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(clients_mutex);
|
|
clients.push_back(client_sock);
|
|
}
|
|
|
|
std::thread(handle_client, client_sock, client_addr).detach();
|
|
std::thread(send_heartbeat, client_sock).detach();
|
|
}
|
|
}
|
|
|
|
void send_heartbeat(int client_sock) {
|
|
while (true) {
|
|
send(client_sock, "KEEP_ALIVE", 10, 0);
|
|
sleep(HEARTBEAT_INTERVAL);
|
|
}
|
|
}
|
|
|
|
void handle_client(int client_sock, sockaddr_in addr) {
|
|
char buffer[1024] = {0};
|
|
fd_set read_fds;
|
|
struct timeval timeout;
|
|
|
|
while (true) {
|
|
FD_ZERO(&read_fds);
|
|
FD_SET(client_sock, &read_fds);
|
|
timeout.tv_sec = 1;
|
|
timeout.tv_usec = 0;
|
|
|
|
int activity = select(client_sock + 1, &read_fds, NULL, NULL, &timeout);
|
|
if (activity < 0) {
|
|
perror("select error");
|
|
break;
|
|
}
|
|
|
|
if (FD_ISSET(client_sock, &read_fds)) {
|
|
int bytes_read = recv(client_sock, buffer, 1024, 0);
|
|
if (bytes_read <= 0) {
|
|
break;
|
|
}
|
|
|
|
if (strncmp(buffer, "ALIVE", 5) == 0) {
|
|
std::cout << "[RECV] Client " << client_sock << " sent ALIVE" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup_disconnected(client_sock);
|
|
close(client_sock);
|
|
std::cout << "[-] Client " << client_sock << " disconnected" << std::endl;
|
|
}
|
|
|
|
void cleanup_disconnected(int client_sock) {
|
|
std::lock_guard<std::mutex> lock(clients_mutex);
|
|
auto it = std::remove(clients.begin(), clients.end(), client_sock);
|
|
clients.erase(it, clients.end());
|
|
}
|
|
|
|
} // namespace Heartbea
|
|
// 111
|
|
// 主函数入口
|
|
// int main() {
|
|
// Heartbeat::start_server();
|
|
// return 0;
|
|
// }
|