Game Development Reference
In-Depth Information
uint8_t GetOpCode() const;
bool IsFinal() const;
bool IsMasked() const;
...
};
A WebSocketMessageHeader will always be at least 16 bits long, so the only data element defined inside the
struct is
short_header
. Accessing the mask and extended payload lengths or the payload is done with an offset from
&short_header
. When I want to parse a header, I simply do this:
WebSocketMessageHeader* header = &buffer[i];
I have found this approach to be very clean; it is generally useful when dealing with structures that do not have a
fixed length or layout.
Messages can be split into multiple fragments. When this happens, the
FINAL-FRAGMENT
bit will be zero until the
final message. The first fragment will have the opcode indicating either a text (
0x1
) or binary (
0x2
) message, and the
rest of the fragments will have the opcode of continuation (
0x0
).
The protocol supports ping (
0x9
) and pong (
0xA
) messages. When a ping message has a payload, the consequent
pong message must have an identical payload. You are only required to pong the most recent ping if more than one
ping arrives.
A WebSocket Server
Now that the WebSocket protocol is understood, I will describe the high-level design of my WebSocket server. My
server uses three buffers: one for incoming WebSocket data, one for outgoing WebSocket data, and one to store fully
parsed incoming messages. Listing 10-8 shows an outline of the API.
Listing 10-8.
Outline of the WebSocket Server API
class WebSocketServer {
public:
WebSocketServer();
int AcceptConnection(TcpListener* listener);
int CloseConnection();
void Update();
int SendTextMessage(const char* msg);
int SendTextMessage(const char* msg, size_t msg_length);
uint64_t PendingMessageCount() const;
void ProcessMessages(OnMessageDelegate del, void* userdata);
void ClearMessages();
};