refactor(server): networking and fix mem leak.
This commit is contained in:
parent
5944663017
commit
5b30ab67c1
@ -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.. */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
122
srv/main.cpp
122
srv/main.cpp
@ -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,68 +55,85 @@ int main(void) {
|
|||||||
|
|
||||||
/* Main server loop. */
|
/* Main server loop. */
|
||||||
while(true) {
|
while(true) {
|
||||||
/* Accept new connections. */
|
fd_set read_fds;
|
||||||
BettolaLib::Network::Socket* client_socket = server_socket.accept();
|
FD_ZERO(&read_fds);
|
||||||
if(client_socket != nullptr) {
|
FD_SET(server_socket.get_sockfd(), &read_fds);
|
||||||
Player* new_player = game.add_player(client_socket);
|
int max_fd = server_socket.get_sockfd();
|
||||||
printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id());
|
|
||||||
|
|
||||||
BettolaLib::Network::MessageHeader header;
|
for(const auto& client : client_sockets) {
|
||||||
header.type = BettolaLib::Network::MessageType::PlayerId;
|
FD_SET(client->get_sockfd(), &read_fds);
|
||||||
header.size = sizeof(unsigned int);
|
if(client->get_sockfd() > max_fd) {
|
||||||
client_socket->send(&header, sizeof(header));
|
max_fd = client->get_sockfd();
|
||||||
unsigned int id = new_player->get_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);
|
|
||||||
if(client_flags == -1) {
|
|
||||||
perror("fcntl F_GETFL failed");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
client_sockets.push_back(client_socket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process messages from clients. */
|
struct timeval tv;
|
||||||
for(auto it = client_sockets.begin(); it != client_sockets.end();) {
|
tv.tv_sec = 0;
|
||||||
BettolaLib::Network::Socket* client = *it;
|
tv.tv_usec = 1000; /* 1ms */
|
||||||
bool client_disconnected = false;
|
|
||||||
|
|
||||||
while(true) {
|
int activity = select(max_fd+1, &read_fds, nullptr, nullptr, &tv);
|
||||||
BettolaLib::Network::MessageHeader header;
|
|
||||||
/* Non-blocking. */
|
|
||||||
ssize_t bytes_received = client->recv(&header, sizeof(header));
|
|
||||||
|
|
||||||
if(bytes_received == 0) {
|
if(activity > 0) {
|
||||||
client_disconnected = true;
|
if(FD_ISSET(server_socket.get_sockfd(), &read_fds)) {
|
||||||
break;
|
BettolaLib::Network::Socket* client_socket = server_socket.accept();
|
||||||
}
|
if(client_socket != nullptr) {
|
||||||
|
Player* new_player = game.add_player(client_socket);
|
||||||
|
printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id());
|
||||||
|
|
||||||
if(bytes_received < 0) {
|
BettolaLib::Network::MessageHeader header;
|
||||||
/* No data to read.. */
|
header.type = BettolaLib::Network::MessageType::PlayerId;
|
||||||
break;
|
header.size = sizeof(unsigned int);
|
||||||
}
|
client_socket->send(&header, sizeof(header));
|
||||||
|
unsigned int id = new_player->get_id();
|
||||||
|
client_socket->send(&id, sizeof(id));
|
||||||
|
|
||||||
if(header.type == BettolaLib::Network::MessageType::PlayerPosition) {
|
int client_flags = fcntl(client_socket->get_sockfd(), F_GETFL, 0);
|
||||||
BettolaLib::Network::PlayerPosMessage msg;
|
fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK);
|
||||||
bytes_received = client->recv(&msg, sizeof(msg));
|
|
||||||
if(bytes_received > 0) {
|
client_sockets.push_back(client_socket);
|
||||||
Player* player = game.get_player_by_socket(client);
|
|
||||||
if(player) {
|
|
||||||
game.update_player_pos(player->get_id(), msg.x, msg.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(client_disconnected) {
|
for(auto it = client_sockets.begin(); it != client_sockets.end();) {
|
||||||
Player* player = game.get_player_by_socket(client);
|
BettolaLib::Network::Socket* client = *it;
|
||||||
if(player) game.remove_player(player->get_id());
|
if(FD_ISSET(client->get_sockfd(), &read_fds)) {
|
||||||
it = client_sockets.erase(it);
|
bool client_disconnected = false;
|
||||||
} else {
|
while (true) {
|
||||||
++it;
|
BettolaLib::Network::MessageHeader header;
|
||||||
|
ssize_t bytes_received = client->recv(&header, sizeof(header));
|
||||||
|
|
||||||
|
if(bytes_received == 0) {
|
||||||
|
client_disconnected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bytes_received < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.type == BettolaLib::Network::MessageType::PlayerPosition) {
|
||||||
|
BettolaLib::Network::PlayerPosMessage msg;
|
||||||
|
bytes_received = client->recv(&msg, sizeof(msg));
|
||||||
|
if(bytes_received > 0) {
|
||||||
|
Player* player = game.get_player_by_socket(client);
|
||||||
|
if(player) {
|
||||||
|
game.update_player_pos(player->get_id(), msg.x, msg.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client_disconnected) {
|
||||||
|
Player* player = game.get_player_by_socket(client);
|
||||||
|
if(player) game.remove_player(player->get_id());
|
||||||
|
it = client_sockets.erase(it);
|
||||||
|
delete client;
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +141,7 @@ int main(void) {
|
|||||||
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. */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user