refactor(server): networking and fix mem leak.

This commit is contained in:
Ritchie Cunningham 2025-09-13 22:21:53 +01:00
parent 5944663017
commit 5b30ab67c1
2 changed files with 80 additions and 61 deletions

View File

@ -1,4 +1,5 @@
#include <algorithm> #include <algorithm>
#include <string.h>
#include "game.h" #include "game.h"
#include "network/game_state_message.h" #include "network/game_state_message.h"
@ -13,8 +14,12 @@ Player* Game::add_player(BettolaLib::Network::Socket* socket) {
void Game::remove_player(unsigned int player_id) { void Game::remove_player(unsigned int player_id) {
_players.erase( _players.erase(
std::remove_if(_players.begin(), _players.end(), std::remove_if(_players.begin(), _players.end(),
[player_id](const Player* player) { [player_id](Player* player) {
return player->get_id() == player_id; if(player->get_id() == player_id) {
delete player;
return true;
}
return false;
}), }),
_players.end()); _players.end());
} }
@ -32,6 +37,7 @@ void Game::update_player_pos(unsigned int player_id, float x, float y) {
void Game::broadcast_game_state(void) { void Game::broadcast_game_state(void) {
BettolaLib::Network::GameStateMessage msg; BettolaLib::Network::GameStateMessage msg;
msg.num_players = _players.size(); msg.num_players = _players.size();
memset(msg.players, 0, sizeof(msg.players));
for(size_t i = 0; i < _players.size(); ++i) { for(size_t i = 0; i < _players.size(); ++i) {
msg.players[i].player_id = _players[i]->get_id(); msg.players[i].player_id = _players[i]->get_id();
@ -45,13 +51,8 @@ void Game::broadcast_game_state(void) {
for(const auto& player : _players) { for(const auto& player : _players) {
BettolaLib::Network::Socket& socket = player->get_socket(); BettolaLib::Network::Socket& socket = player->get_socket();
/* Just quick fix the server crash for now. */ socket.send(&header, sizeof(header));
if(socket.send(&header, sizeof(header)) <= 0) { socket.send(&msg, sizeof(msg));
/* TODO: Probably should handle this error by removing player.. */
}
if(socket.send(&msg, sizeof(msg)) <= 0) {
/* TODO: Probably should handle this error by removing player.. */
}
} }
} }

View File

@ -1,6 +1,7 @@
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <chrono> #include <chrono>
#include <sys/select.h>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <fcntl.h> #include <fcntl.h>
@ -54,7 +55,26 @@ int main(void) {
/* Main server loop. */ /* Main server loop. */
while(true) { while(true) {
/* Accept new connections. */ fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_socket.get_sockfd(), &read_fds);
int max_fd = server_socket.get_sockfd();
for(const auto& client : client_sockets) {
FD_SET(client->get_sockfd(), &read_fds);
if(client->get_sockfd() > max_fd) {
max_fd = client->get_sockfd();
}
}
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000; /* 1ms */
int activity = select(max_fd+1, &read_fds, nullptr, nullptr, &tv);
if(activity > 0) {
if(FD_ISSET(server_socket.get_sockfd(), &read_fds)) {
BettolaLib::Network::Socket* client_socket = server_socket.accept(); BettolaLib::Network::Socket* client_socket = server_socket.accept();
if(client_socket != nullptr) { if(client_socket != nullptr) {
Player* new_player = game.add_player(client_socket); Player* new_player = game.add_player(client_socket);
@ -67,25 +87,19 @@ int main(void) {
unsigned int id = new_player->get_id(); unsigned int id = new_player->get_id();
client_socket->send(&id, sizeof(id)); client_socket->send(&id, sizeof(id));
/* Set the client socket to non-blocking. */
int client_flags = fcntl(client_socket->get_sockfd(), F_GETFL, 0); int client_flags = fcntl(client_socket->get_sockfd(), F_GETFL, 0);
if(client_flags == -1) {
perror("fcntl F_GETFL failed");
return 1;
}
fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK); fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK);
client_sockets.push_back(client_socket); client_sockets.push_back(client_socket);
} }
}
/* Process messages from clients. */
for(auto it = client_sockets.begin(); it != client_sockets.end();) { for(auto it = client_sockets.begin(); it != client_sockets.end();) {
BettolaLib::Network::Socket* client = *it; BettolaLib::Network::Socket* client = *it;
if(FD_ISSET(client->get_sockfd(), &read_fds)) {
bool client_disconnected = false; bool client_disconnected = false;
while (true) { while (true) {
BettolaLib::Network::MessageHeader header; BettolaLib::Network::MessageHeader header;
/* Non-blocking. */
ssize_t bytes_received = client->recv(&header, sizeof(header)); ssize_t bytes_received = client->recv(&header, sizeof(header));
if(bytes_received == 0) { if(bytes_received == 0) {
@ -94,7 +108,6 @@ int main(void) {
} }
if(bytes_received < 0) { if(bytes_received < 0) {
/* No data to read.. */
break; break;
} }
@ -114,16 +127,21 @@ int main(void) {
Player* player = game.get_player_by_socket(client); Player* player = game.get_player_by_socket(client);
if(player) game.remove_player(player->get_id()); if(player) game.remove_player(player->get_id());
it = client_sockets.erase(it); it = client_sockets.erase(it);
delete client;
} else { } else {
++it; ++it;
} }
} else {
++it;
}
}
} }
/* Broadcase game state. */ /* Broadcase game state. */
game.broadcast_game_state(); game.broadcast_game_state();
/* Sleep for a short time to avoid busy-waiting. */ /* Sleep for a short time to avoid busy-waiting. */
std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
server_socket.close(); /* Shouldn't reach here. */ server_socket.close(); /* Shouldn't reach here. */