Files
esDashboard/src/Network/Server/Server.cpp
T
2025-12-25 13:00:42 +00:00

109 lines
2.7 KiB
C++

#include "Network/Server/Server.h"
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include "Metrics/Host.h"
namespace Network
{
Server::Server(uint16_t port, Model::HostRegistry &registry)
: port_(port), registry_(registry), running_(false)
{
sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd_ < 0)
throw std::runtime_error("Failed to create UDP socket");
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port_);
if (bind(sockfd_, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) < 0)
{
throw std::runtime_error("Failed to bind UDP socket");
}
}
Server::~Server()
{
stop();
close(sockfd_);
}
void Server::start()
{
running_ = true;
serverThread_ = std::thread(&Server::run, this);
}
void Server::stop()
{
running_ = false;
if (serverThread_.joinable())
serverThread_.join();
}
void Server::run()
{
constexpr size_t BUF_SIZE = 4096;
uint8_t buffer[BUF_SIZE];
while (running_)
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd_, &readfds);
timeval tv{};
tv.tv_sec = 0;
tv.tv_usec = 500 * 1000; // 500 ms
int ret = select(sockfd_ + 1, &readfds, nullptr, nullptr, &tv);
if (ret < 0)
{
if (errno == EINTR)
continue;
perror("select");
break;
}
if (ret == 0)
{
// timeout — просто проверяем running_
continue;
}
if (FD_ISSET(sockfd_, &readfds))
{
sockaddr_in clientAddr{};
socklen_t addrLen = sizeof(clientAddr);
ssize_t len = recvfrom(
sockfd_,
buffer,
BUF_SIZE,
0,
reinterpret_cast<sockaddr *>(&clientAddr),
&addrLen);
if (len <= 0)
continue;
try
{
std::vector<uint8_t> data(buffer, buffer + len);
auto metrics = Metrics::Host::deserialize(data);
registry_.update(metrics.hostname, metrics);
}
catch (const std::exception &e)
{
std::cerr << "UDP parse error: " << e.what() << std::endl;
}
}
}
}
} // namespace Network