feat(server) Implement binary messaging protocol.

This commit is contained in:
Ritchie Cunningham 2025-09-13 16:33:38 +01:00
parent 6e935918a3
commit d21a0df285
6 changed files with 68 additions and 50 deletions

View File

@ -0,0 +1,16 @@
#pragma once
namespace BettolaLib {
namespace Network {
enum class MessageType : unsigned char {
PlayerPosition,
};
struct MessageHeader {
MessageType type;
unsigned short size;
};
} /* namespace Network. */
} /* namespace BettolaLib. */

View File

@ -0,0 +1,14 @@
#pragma once
#include "message.h"
namespace BettolaLib {
namespace Network {
struct PlayerPosMessage {
float x;
float y;
};
} /* namespace Network. */
} /* namespace BettolaLib. */

View File

@ -88,12 +88,16 @@ bool Socket::connect(const std::string& ip_address, unsigned short port) {
_address.sin_family = AF_INET; _address.sin_family = AF_INET;
_address.sin_port = htons(port); _address.sin_port = htons(port);
if(inet_pton(AF_INET, ip_address.c_str(), &_address.sin_addr) <= 0) { int pton_ret = inet_pton(AF_INET, ip_address.c_str(), &_address.sin_addr);
perror("Invalid address / Address not supported."); if(pton_ret == 0) {
fprintf(stderr, "Invalid address format\n");
return false;
} else if(pton_ret == -1) {
perror("inet_pton failed");
return false; return false;
} }
if(::connect(_sockfd, (struct sockaddr*)&_address, sizeof(_address)) <= 0) { if(::connect(_sockfd, (struct sockaddr*)&_address, sizeof(_address)) == -1) {
fprintf(stderr, "Socket::connect() failed for sockfd %d with errno %d: %s\n", _sockfd, fprintf(stderr, "Socket::connect() failed for sockfd %d with errno %d: %s\n", _sockfd,
errno, strerror(errno)); errno, strerror(errno));
perror("Connection failed."); perror("Connection failed.");

View File

@ -11,6 +11,8 @@
#include "bettola.h" #include "bettola.h"
#include "bettola/network/socket.h" #include "bettola/network/socket.h"
#include "bettola/network/net_common.h" #include "bettola/network/net_common.h"
#include "network/message.h"
#include "network/player_pos_message.h"
/* Dacav's resolution ;) */ /* Dacav's resolution ;) */
const int SCREEN_WIDTH = 800; const int SCREEN_WIDTH = 800;
@ -82,10 +84,16 @@ int Bettola::run(void) {
network_time += delta_time; network_time += delta_time;
if(network_time > 2.0) { if(network_time > 2.0) {
/* Send/receive every 2 seconds. */ /* Send/receive every 2 seconds. */
send_data("Player position: " + std::to_string(_player.get_x()) + "," + BettolaLib::Network::MessageHeader header;
std::to_string(_player.get_y())); header.type = BettolaLib::Network::MessageType::PlayerPosition;
std::string response = receive_data(); header.size = sizeof(BettolaLib::Network::PlayerPosMessage);
printf("Bettola Client (in game loop): Received: '%s'\n", response.c_str()); _client_socket.send(&header, sizeof(header));
BettolaLib::Network::PlayerPosMessage msg;
msg.x = _player.get_x();
msg.y = _player.get_y();
_client_socket.send(&msg, sizeof(msg));
network_time = 0.0; network_time = 0.0;
} }
@ -237,6 +245,7 @@ void Bettola::setup_quad(void) {
} }
bool Bettola::init_client_connection(void) { bool Bettola::init_client_connection(void) {
SDL_Delay(1000); /* Wait a second before trying to connect. */
if(!_client_socket.create()) { if(!_client_socket.create()) {
printf("Bettola client: Failed to create socket.\n"); printf("Bettola client: Failed to create socket.\n");
return false; return false;
@ -252,28 +261,3 @@ bool Bettola::init_client_connection(void) {
return true; return true;
} }
void Bettola::send_data(const std::string& data) {
ssize_t bytes_sent = _client_socket.send(data.c_str(), data.length());
if(bytes_sent == -1) {
perror("Bettola Client: Failed to send data.");
} else {
printf("Bettola Client: Sent %zd bytes: '%s'\n", bytes_sent, data.c_str());
}
}
std::string Bettola::receive_data(void) {
char buffer[256]; /* Just a small buffer currently. */
ssize_t bytes_received = _client_socket.recv(buffer, sizeof(buffer) - 1);
if(bytes_received == -1) {
perror("Bettola Client: Failed to receive data.");
return "";
} else if(bytes_received == 0) {
printf("Bettola Client: Server disconnected.\n");
/* Attempt to reconnect. */
_client_socket.close(); /* Close the old socket. */
return "";
}
buffer[bytes_received] = '\0';
return std::string(buffer);
}

View File

@ -25,8 +25,6 @@ private:
bool create_gl_context(void); bool create_gl_context(void);
bool init_client_connection(void); bool init_client_connection(void);
void send_data(const std::string& data);
std::string receive_data(void);
void setup_quad(void); void setup_quad(void);

View File

@ -2,6 +2,8 @@
#include "bettola/network/socket.h" #include "bettola/network/socket.h"
#include "bettola/network/net_common.h" #include "bettola/network/net_common.h"
#include "bettola/network/message.h"
#include "bettola/network/player_pos_message.h"
int main(void) { int main(void) {
printf("=== Bettola Server: Starting ===\n"); printf("=== Bettola Server: Starting ===\n");
@ -39,23 +41,23 @@ int main(void) {
printf("Bettola Server: Client connected!\n"); printf("Bettola Server: Client connected!\n");
char buffer[256]; /* Small buffer for echo. */ while(true) {
ssize_t bytes_received; BettolaLib::Network::MessageHeader header;
do { ssize_t bytes_received = client_socket->recv(&header, sizeof(header));
bytes_received = client_socket->recv(buffer, sizeof(buffer) - 1);
if(bytes_received > 0) {
buffer[bytes_received] = '\n';
printf("Bettola Server: Received from client: '%s'\n", buffer);
client_socket->send(buffer, bytes_received); /* Echo back. */
} else if(bytes_received == -1) {
perror("Bettola Server: Error receiving from client.");
}
} while(bytes_received > 0);
/* Let's just keep it connected for now. */ if(bytes_received <= 0) {
// printf("Bettola Server: Client disconnected.\n"); break;
// client_socket->close(); }
// delete client_socket;
if(header.type == BettolaLib::Network::MessageType::PlayerPosition) {
BettolaLib::Network::PlayerPosMessage msg;
bytes_received = client_socket->recv(&msg, sizeof(msg));
if(bytes_received > 0) {
printf("Bettola Server: Received PlayerPosition messgae: x=%.2f, y=%.2f\n",
msg.x, msg.y);
}
}
}
} }
server_socket.close(); /* Shouldn't reach here. */ server_socket.close(); /* Shouldn't reach here. */