Developer Documentation
Overview
The NetworkingService
class manages real-time communication between clients and servers using the Game Datagram Transfer Protocol (GDTP) over UDP. It supports sending and receiving game-related data such as player movements, entity updates, and events. This class is designed to ensure low-latency communication, making it suitable for real-time multiplayer game environments.
Class: NetworkingService
Key Characteristics:
- Transport Layer: Uses UDP for low-latency, high-speed communications.
- Asynchronous I/O: Leverages ASIO for non-blocking network operations.
- Event-Driven Architecture: Uses handlers for processing specific message types.
- Singleton Pattern: Ensures a single instance of the service for consistent network behavior across the application.
Protocol Overview:
The GDTP protocol uses a fixed header structure:
- Version (1 byte): Protocol version (currently
0x01
). - Message Type (1 byte): Identifies the type of message.
- Packet ID (8 bytes): Unique identifier for the packet.
- Payload Size (2 bytes): The size of the message payload.
- Sequence Number (2 bytes): Order of the packet in a sequence.
- Total Packets (2 bytes): Indicates how many packets make up the full message.
Public Methods
static NetworkingService& getInstance(const std::string& server_ip = "127.0.0.1", int port = 12345)
- Description: Retrieves the singleton instance of
NetworkingService
, creating it if it doesn't exist. - Parameters:
server_ip
(const std::string&): IP address of the server.port
(int): The port number for communication.
- Example:
NetworkingService& networkService = NetworkingService::getInstance("192.168.1.10", 8080);
networkService.run(); // Start the service.
void addEvent(const uint8_t messageType, const std::function<void(const GDTPHeader&, const std::vector<uint8_t>&, const asio::ip::udp::endpoint&)>& handler)
- Description: Registers a handler function for a specific GDTP message type. When a message of this type is received, the registered function is called.
- Parameters:
messageType
(uint8_t): The type of message for which the handler is being registered.handler
: A function that processes the message's header, payload, and client endpoint.
- Example:
networkService.addEvent(0x01, [](const GDTPHeader& header, const std::vector<uint8_t>& payload, const asio::ip::udp::endpoint& client) {
std::cout << "Player movement received from " << client.address() << std::endl;
});
std::string getLocalEndpoint() const
- Description: Retrieves the local endpoint (IP:Port) where the service is listening.
- Returns: A string representation of the local endpoint.
- Example:
std::string endpoint = networkService.getLocalEndpoint();
std::cout << "Listening on: " << endpoint << std::endl;
std::string getIp() const
- Description: Retrieves the local IP address where the service is listening.
- Returns: The IP address as a string.
- Example:
std::string ip = networkService.getIp();
std::cout << "Local IP: " << ip << std::endl;
uint32_t getPort() const
- Description: Retrieves the local port number where the service is listening.
- Returns: The port number.
- Example:
uint32_t port = networkService.getPort();
std::cout << "Listening on port: " << port << std::endl;
Sending and Receiving Messages
void sendRequest(const std::string& recipient, int port, uint8_t messageType, const std::vector<uint8_t>& payload = {})
- Description: Sends a message with a specified type and payload to a recipient.
- Parameters:
recipient
: IP address of the recipient.port
: Port number on which to send the message.messageType
: Type of message (e.g.,0x01
for PlayerMovement).payload
: Data to be included in the message.
- Example:
std::vector<uint8_t> data = {0x01, 0x02, 0x03};
networkService.sendRequest("127.0.0.1", 12345, 0x01, data);
void sendRequest(const asio::ip::udp::endpoint& client_endpoint, uint8_t messageType, const std::vector<uint8_t>& payload = {})
- Description: Sends a message directly to a specified client endpoint.
- Example:
asio::ip::udp::endpoint client(asio::ip::make_address("127.0.0.1"), 12345);
networkService.sendRequest(client, 0x01, {0x10, 0x20});
void sendRequestResponse(const std::string& recipient, int port, GDTPHeader headerOrigin, const std::vector<uint8_t>& payload = {})
- Description: Sends a response using a given header and payload.
- Parameters:
headerOrigin
: Original header used as the basis for the response.
- Example:
GDTPHeader header = ...; // Received from another message
networkService.sendRequestResponse("127.0.0.1", 12345, header, {0xAA, 0xBB});
Internal Methods
void startReceive()
- Description: Starts listening for incoming packets asynchronously.
- Example:
networkService.startReceive(); // Begin listening for messages.
void handleReceivedPacket(const std::array<uint8_t, 1400>& packet, std::size_t length, const asio::ip::udp::endpoint& client_endpoint) const
- Description: Validates and processes an incoming packet.
- Example:
handleReceivedPacket(buffer, length, client_endpoint);
void processMessage(uint8_t messageType, const std::vector<uint8_t>& payload, const GDTPHeader& header, const asio::ip::udp::endpoint& client_endpoint) const
- Description: Processes a message by invoking the appropriate handler.
- Example:
processMessage(0x01, payload, header, client_endpoint);
Best Practices for Developers
-
Starting the Service:
- Call
getInstance()
to create or retrieve the singleton instance. - Use
startReceive()
followed byrun()
to start receiving messages. - Example:
auto& service = NetworkingService::getInstance();
service.startReceive();
service.run();
- Call
-
Adding Event Handlers:
- Use
addEvent()
to register handlers for different message types. - Ensure each handler processes the payload correctly according to its type.
- Example:
service.addEvent(0x05, [](const GDTPHeader& header, const std::vector<uint8_t>& payload, const asio::ip::udp::endpoint& client) {
std::cout << "Handling a Player Shoot event." << std::endl;
});
- Use
-
Shutting Down the Service:
- Call
stop()
before the application exits to gracefully close network operations. - Use
attempt()
to wait until the network thread is fully stopped. - Example:
service.stop();
service.attempt();
- Call
-
Sending Requests and Responses:
- Use
sendRequest()
to send messages to clients or servers. - Use
sendRequestResponse()
to reply to received messages, preserving header metadata.
- Use