As I've recently been playing around with various programs which communicate with each other via TCP/IP, I've decided that I needed some sort of simple protocol to make certain that the data I send and receive from computer to computer is correct and not corrupted. Here's the routine I've basically set up so far:
COLOR &HFFFFFFFF, &HFF000000 Host
= _OPENHOST("TCP/IP:7990") ' this will be the host code
Player = GetClient 'Not
PRINT "New Player connected" 'Do stuff
UserData$ = In$(Player)
'do stuff with the data the user sent
'and close the connection
Player = 0
'CHR$(2) = Start of Text
'CHR$(3) = End of Text
'CHR$(4) = End of Transmission (It's what we use to tell the client, "We give up! Closing connection!"
'CHR$(6) = Acknowledge
'CHR$(15) = Not Acknowledge
GET #who
, , b
'just check for a single byte from each connection
'If we get something which isn't a CHR$(2) to start communication, send back a failure notice.
SendError who
EXIT FUNCTION 'Exit so we can move on to the next connection to check for that leading chr$(2)
'Only if that initial byte is CHR$(2), do we acknowledge receipt and await further messages.
SendConfirmation who 'we send ACKnowledgement back to tell the client we're ready for them to talk to us.
count = count + 1
timeout## = ExtendedTimer + 5
_LIMIT 100 'no need to check for incoming information more than 100 times a second! IF a$
<> "" THEN tempIn$
= tempIn$
+ a$
'tempIn$ should never be more than 105 bytes ETX
= INSTR(a$
, CHR$(3)) ' chr$(3) is our ETX character (End of TeXt) IF ExtendedTimer
> timeout##
THEN 'If it takes over 5 seconds to send 100 bytes (or less) of info SendError who ' something is wrong. Terminate the attempt, but be nice, and let
EXIT FUNCTION ' the other client know something went wrong, so they can try again, END IF ' if they want to. LOOP UNTIL LEN(tempIn$
) > 105 'If we have over 105 bytes with our string, we didn't send the data properly. SendError who 'send the client an error message
tempIn$
= _TRIM$(LEFT$(tempIn$
, ETX
- 1)) 'strip off the ETX character and check to make certain data is valid.
c$
= RIGHT$(tempIn$
, 4) 'these 4 bytes are the checksum
CheckSum
= CVL(c$
) 'Check to make certain the data apprears valid. IF CheckSum
<> Check
THEN ' Our data is not what we expected. Part may be lost, or corrupted. SendError who
SendConfirmation who
'If we get bad data 5 times in a row, something is wrong. We're just going to close the connection.
SendError who
'and if we're down this far, our data has been recieved, verified, and is now good to use.
In$
= LEFT$(tempIn$
, 4) 'left part of the string is the data the user is sending us
b = 4
SUB SendConfirmation
(who
) b = 6
SELECT CASE m
'Add the number of days for each previous month passed IF (y
MOD 4) = 2 AND m
> 2 THEN d
= d
+ 1 'add a day if this is leap year and we're past february d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
d = d + (y + 2) \ 4 'add in days for leap years passed
s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
ExtendedTimer##
= (s
+ TIMER)
Now this isn't going to work to send binary files, as I'm using some of the ASCII characters as reserved command codes, but since this isn't meant to be a file transfer protocol, I don't think it should be a problem. My command codes are as follows:
'CHR$(2) = Start of Text
'CHR$(3) = End of Text
'CHR$(4) = End of Transmission (It's what we use to tell the client, "We give up! Closing connection!"
'CHR$(6) = Acknowledge
'CHR$(15) = Not Acknowledge
The idea the behind the process is this one:
First, we simply wait for a CHR$(2) character to come in, as a request from a client saying they want to send us data. If we get anything else before that, we send them an error message. All messages start with chr$(2), and when we get it, we send a confirmation back to the client so they know we're all set to receive their data (CHR$(6)).
At this point, they send us the data, which is limited to being 105 bytes or less. This 105 byte structure consists of up to 100 bytes of data, 4 bytes for a checksum of the data sent, and then the termination code. (CHR$(3))
Once we verify that everything is correct, we either send back a success, or failure signal, to the client. If we fail, they can try to resend the data, otherwise all is golden.
I tried to comment the process here so that it'd be easily understood by anyone who looks it over, but if anyone has any questions, just ask them. If there appears to be something wrong with my logic, feel free to tell me about that as well. I haven't actually tested this in a working program yet (my test game is still in development and hasn't gotten to the point where it's trying to talk back and forth to other games yet), but I don't see anything that looks wrong with it. Unless I just made a common typo, or other silly mistake, it should work as intended here...
Take a look at it. See if it looks like a process that will hold up to general usage to send plain text back and forth between computers. And, if you see something that I goofed on, or overlooked, kindly point it out to me. If all works as intended, this will end up going into a transfer library later for me, so I can just plug it into any project and use it to send and receive data between devices. :)