This tutorial will guide the user on how to create a console program that utilises networking within Swingame, and specifically the TCP protocol. The source code for this program was written with hardcoded values in order to simplify the code so that it can demonstrate the bare minimum necessary code to connect and send messages using TCP. Both the client and Host can be run with the same code, which can be compiled once and launched twice. This program does not launch the game window, and input/output is done in the console.
Let’s look at the main procedure of the program. It tells us the main functions that will be called, as well as the main variables used.
procedure Main(); var lIsHost : Boolean = False; lPeer : Connection = nil; begin lIsHost := SelectPeerType(); if (lIsHost) then lPeer := WaitForConnections() else lPeer := WaitToConnectToHost(); HandleMessages(lPeer, lIsHost); ReleaseAllResources(); end;
The lIsHost Boolean tells us whether this peer is the host or just a client connecting to the host.
· lPeer is the Connection data, that will be used to send and retrieve messages.
In the body of the main procedure, it can be seen that we:
· Select the peer type
· Wait for Connections (if Host) or
· Wait to connect to the host (if not host)
· Handle Messages
· Release our resources.
Let’s look at this in more depth. First, the Select Peer type function.
function SelectPeerType() : Boolean; var lInput : String = ''; begin Write('Are You Hosting? [y/n]: '); while (lInput <> 'y') and (lInput <> 'n') do begin ReadLn(lInput); if (lInput = 'y') then begin CreateTCPHost(HOST_PORT); result := True; WriteLn('I am now the host'); end else if (lInput = 'n') then begin result := False; WriteLn('I am now the client'); end; end; end;
The purpose of this function is to establish whether the program is set as the host or a client. The user is asked to enter ‘y’ to host, or ‘n’ to be a client that connects to the host.
If the user selects to be the host, a socket is bound to a hardcoded port HOST_PORT using the CreateTCPHost function. The program will then listen on this port for new connections. This function will then return true, as the program has been delegated as the host.
If the user selects to be a client with the intent to connect to a host, the function will return False, and do nothing else within this function.
This setup allows the program to continue onto the next step. Since the Host and Client have been established, the program will now connect the two in the next step.
function WaitForConnections() : Connection; begin WriteLn('Waiting for Connections....'); result := nil; while (result = nil) do begin AcceptTCPConnection(); result := FetchConnection(); end; WriteLn('Connection Established.'); end; function WaitToConnectToHost() : Connection; begin WriteLn('Connecting to Host....'); result := nil; while (result = nil) do result := CreateTCPConnection('127.0.0.1', HOST_PORT); WriteLn('Connected to Host'); end;
The two functions to look at are WaitToConnectToHost and WaitForConnections.
If the program is the Host, it will loop until it receives a connection. The AcceptTCPConnection function is used to accept new connections. The loop however, terminates when the result is not nil. In the loop, the result is being assigned to the result of FetchConnection. When a new connection is accepted by the program, it puts the connection into a queue of new connections. These connections can then be fetched and assigned for easier access in the program. This will remove the connection from the new connection list. If there are no new connections, FetchConnection will return nil, as is the case before a connection has been received. Therefore, this loop will terminate when the program has successfully fetched a new connection.
The WaitToConnectToHost is what is called for by the client designated program. It loops until it is able to connect to the host. The CreateTCPConnection method takes in theIP of the host, and the port the host is listening on. These values were hardcoded for this program, but you can ask for user input for these values. Failing to create the connection will return a nil value, which is what is set to result. As the loop terminates when result is not nil, it will keep looping until a successful connection is made.
Both functions should complete their loop at a similar time, which should allow the program to move onto the next phase – sending messages.
procedure HandleMessages(const aPeer : Connection; const aIsHost : Boolean); var lMessage : String = ''; i : Integer; const AUTO_MESSAGE_COUNT = 10; SEND_DELAY = 1500; begin for i := 0 to AUTO_MESSAGE_COUNT do begin if (aIsHost) then SendTCPMessage('Hello. This Message Number ['+IntToStr(i)+'] is from the Host. The client should receive it.', aPeer) else SendTCPMessage('Hello. This Message Number ['+IntToStr(i)+'] is from the Client. The host should receive it.', aPeer); Delay(SEND_DELAY); if TCPMessageReceived() then WriteLn('Received Message: ', ReadMessage(aPeer)); end; end;
The HandleMessages procedure handles the sending and receiving of messages. For the purpose of this tutorial, it was set to automatically send and receive message without user input. This is because user input in the console blocks the program with ReadLn. Automatically sending messages allows the program to keep flowing, while showing the output.
This program sends a different message based on if it is the host or client. Regardless of the message sent, the function is still the same, SendTCPMessage. This takes in the connection, and a message string.
The Delay is set because the program is automatically accepting and receiving messages , and it takes longer than one CPU cycle for a message to be sent.
New messages can be queued using the TCPMessageReceived function. This queues the message into the connection it received the message from. It will return true if a new message has been received and false I there was no new messages.
The message can then be read from the connection using the ReadMessage function that takes the connection as a parameter. If there are no messages in the queue it will return an empty string. Reading the message pops it off the queue.
The loop is set to send/receive ten messages before it ends.
This successfully completes Connected, Sending and Receving Messages through the TCP protocol using SwinGame. The final function, RemoveAllResources, will free any pointers created by SwinGame.
If there is a useful hint you will find it in a box like this
Suggested projects will appear here.