UDP Pong - Protocol Design
There's a lot more we have to do here than in the UDP File Transfer app. By design UDP is connectionless, but the problem is that we need to have our clients to be able to establish a connection, maintain it, transfer data in between, and then quit when they want. We'll be implementing these things ourselves.
Basic Packet Structure
The first four bytes of each packet will denote its PacketType
. Instead of encoding some ASCII bytes like we did with the File Transfer example we'll be using 32 bit unsigned integers (4 bytes). The next eight bytes will be a Timestamp
encoded in a signed 64 bit integer (8 bytes). After that will be the Payload
, it's just an array of bytes. It can be empty or it might have something to it. That all depends on the PacketType
. So at minimum all Packet
s will be 12 bytes long.
Types of Packets
Here is what each PacketType
is, with a description:
RequestJoin
- Sent by the Client to the Server requesting to join a game.AcceptJoin
- Sent by the Server to the Client as a response to the above. It contains whichPaddle
the Client will be.AcceptJoinAck
- Sent by the Client the Server to acknowledge the above.Heartbeat
- Sent by the Client to the Server to notify its still connected.HeartbeatAck
- Sent by the Server to the Client to acknowledge the above.GameStart
- Sent by the Server to the Client to notify the game is going to start.GameStartAck
- Sent by the Client to the Server to acknowledge the above.PaddlePosition
- Sent by the Client to the Server to tell itsPaddle
's current position.GameState
- Sent by the Server to the Client to tell it the current state of the game (Paddle
positions, scores,Ball
position, etc.).PlaySoundEffect
- Sent by the Server to the Client to play a sound effect.Bye
- Sent by either the Server or the Client to notify the other it's done with the game.
Connection Establishment
This is our version of the TCP Three-Way Handshake. The Client will send a RequestJoin
to the Server. The Server will respond with an AcceptJoin
message; it is the only one that contains data (an unsigned 32 bit integer that denotes the Client's Paddle
). Then the Client will need to respond with the AcceptJoinAck
. Here is a diagram of the handshake:
Maintaining the Connection
This is pretty simple, the client will send Heartbeat
messages and the server will send back HeartbeatAck
messages in response. The Client and Server will also record the times they got them and use it to determine if a connection has dropped or not. The heartbeat timeout value will be 20 seconds. These are sent after a connection has been established, while waiting for a GameStart
/GameStartAck
, and while the game is being played.
Game Start
The Server will not start the game until two Clients are connected. Once that criteria has been met, it will send out the GameStart
messages. The Clients will both need to respond with a GameStartAck
before the Server will deliver any GameState
messages.
In Game
A few times per second both the Clients and the Server will send each other info about their current state. The Client only needs to send PaddlePosition
Packet
s; it contains one floating point number that is the Paddle
's Y position. The Server will send a GameState
Packet
to both Clients. It will contain the Paddle
& Ball
positions as well as the scores (see the diagram below for the data layout). Periodically the Server will send a PlaySoundEffect
message. This will tell the Client it should play a sound effect. The name of the sound effect is encoded as a UTF-8 string.
Check the code for Packet.cs
for details, specifically the classes GameStatePacket
, PaddlePositionPacket
, and PlaySoundEffect
. They will show you how the data is laid out.
Ending the Connection
At any time a Client or Server could send a Bye
. This simply tells the other that the connection is over. If a Client sends it to the Server while in the middle of a game, the Server then needs to notify the other client the game is over. When the Server shuts down, it should send a Bye
message to all connected Clients.