SDL 2.0 Tutorial-05: Networking 2

In the last tutorial we finished with a hallow if-statement within our processing loop.

If there aren’t any sockets which we need to process (i.e. num_rdy <= 0 ) then we’ll loop over all the currently connected client sockets and perform any tasks which may be pending. This is basically the server’s chance to catch up with game state and perform any security checks. This will work well for a simple TCP game where the server and client need not be in sync the entire time. For something more real-time we would prioritize game state and perhaps use UDP instead.

For now let’s add four wood to the resource count for each connected client.

Remember this will run every second assuming there aren’t any sockets to be processed (i.e. num_rdy <= 0 ). Why am I saying it’ll run every second? It is because of the following function call:

The second argument to this function is 1000, which is the number of milliseconds this function will block while waiting for a socket connection.

Now, if there are sockets ready to be processed we’ll have to check whether it is a client socket or the server socket. If the server socket is ready then we likely have a new client connection. For the client connections we’ll have to check each one until we find the ones which are ready and then process the data that we have received from them.

First let’s handle the case when the server socket is ready:

Here the function  int AcceptSocket(int index); is a shorthand for accepting a new socket connection using  sockets[index] and  clients[index] . This function returns whether or not the connection was successfully accepted. Here is the function itself:

The function  void CloseSocket(int index); was presented in the previous part of this tutorial. After we accept the new client connection we also update the  next_ind variable so that we are ready for the next client connection. As it’s currently written, if a new client connects when the server is full then another client will be kicked to make room for the new connection.

Now let’s process any clients which might have data for us.

What we are doing here is looping over all the client sockets and checking to see whether a client is connected and whether that connected client has some information ready for us. We also want to make sure that we aren’t working harder than we have to by breaking out of the for-loop when  num_rdy == 0 ; because at that point we have processed all the ready client sockets so there is no point in checking any remaining client connections for information.

Once we know that we have a connected socket and that the socket have information ready for us, we fill a buffer with the data they sent us. This is what the  uint8_t* RecvData(int index, uint16_t* length, uint16_t* flag); function does for us:

This function gets data from  sockets[index] and returns a pointer to a new buffer. The in/out function arguments  length and  flag are the length of the newly allocated buffer and the packet flag for the information we are receiving from the client.

If the client sends us a request for the amount of wood they current possess (i.e. FLAG_WOOD_UPDATE ) then we reply by sending them a packet with the information they are requesting. To send information to the connected client we use the following shorthand function:

For debugging purposes the client can also shutdown the server with a  FLAG_QUIT . In the next tutorial we will write a simple client which will display the amount of wood the client current has. This amount will continue to increase because the server currently adds four wood each time it enters idle processing. Once we have achieved this we’ll add a “quest” button and timer on the client-side and a few more packet flags allowing the client to request the amount of time left on a quest and to start a quest. The server will check for when a quest completes and will increase the amount of wood for that client as a result.

Till next time!