TCP-ing from client(s) to a server

Blitz3D Forums/Blitz3D Programming/TCP-ing from client(s) to a server

There is a couple of posts regarding transferring data and the like.

Tried to keep code minimalist so can be expanded further....

Using the client and server code below,compile them and
create a sub directory in the same directory as your compiled server_v2 and client_v2 executables, called file_dir.

This sub directory is used by the server to maintain a list of the clients that are running, without it the VB.net front end will not work.

I have developed a VB.net front end for the two executables server_v2 and client_v2 that keeps a running count of the clients running,
will kill the server and subsequently clean up the file_dir sub directory of historic client files. You do not want
to put any of your own files within the file_dir directory, this directory gets cleaned very well upon Kill Server!

Link to VB.net front end:
http://myweb.tiscali.co.uk/diecastcars/File_Counter.exe

NOTE: Do Not try to run the File_Counter.exe file before you have created a subdirectory call file_dir at the same path. Nothing BAAaaad will happen, it just wont work (;-)
So: You might want once you compile the two slices of code below, called them server_v2.exe and client_v2.exe respectively then put them at the same path as File_Counter.exe, else the start server and client buttons won't find what they need.


Server:

; TCP engine ULTRA FAST
;
; Written by Daniel Eriksson  (daniel@...)
;
; save executable as :
;
; server_v2.exe
;
; for VB.net front end to locate.  Also add a sub-directory
; called "file_dir" for the server to put files associated 
; with clients

; added to by M Gormley, also incorporated
; a VB.net front end which can be used to start
; the server, start clients, monitor how many clients
; are running, kill the server and cleanup files.


;Public Domain free do use as wish including selling it.

;VARS
max_bank=512
global_client_count=0
Dim file_name$(255); 255 possible clients - who'd need more?
Global file_count=0


Type session

	Field link
	Field tcp_sendbank
	Field tcp_recbank
	Field status

End Type

;window=CreateWindow("Key press me window",100,100,640,200,0,1)  BBasic
Graphics 400,700,16,2            ; B3D

server=CreateTCPServer(7056)
Print "server is running.."

msmin=9999999 ; minimums millisecs :D

While Not KeyHit(1)   ;Hehe this command dosent work in BlitzPluss with the console window.

	stream = AcceptTCPStream(server)
	If stream
		global_client_count=global_client_count+1
		Print "New stream detected. memory allocated."
		ses.session = New session
		ses\link=stream
		ses\tcp_sendbank = CreateBank(max_bank)	
		ses\tcp_recbank = CreateBank(max_bank)
		ses\status =10 ; Simulate login.
		;ses\client_count=global_client_count
		
		fn_create_file(Int ses\link)
	
	End If


	oldms=MilliSecs()
	;Validate streams.. 
	For ses.session = Each session
	
		If Eof(ses\link) 
			Print "A session called "+ses\link+" has stop working."
			Print "Frees memory banks for session "+ses\link
			FreeBank ses\tcp_sendbank 
			FreeBank ses\tcp_recbank
			Print "deletes sessions "+ses\link
			
			numberin=ses\link
			fn_delete_file(Int ses\link)
			
			Delete ses
			global_client_count=global_client_count-1
		End If
		
	Next
	
	
	For ses.session = Each session
	
	
		Select ses\status
		Case 10
		
			If ReadAvail(ses\link)>=max_bank
			
				;so we got a new packet :D and its all 100% secure... so we can go on live our lifes
				r=ReadBytes (ses\tcp_recbank,ses\link,0,max_bank)
				Print "for session "+ses\link+" who has a tcp recbank of:"+ses\tcp_recbank
				Print "read "+r+" bytes from stream"
				
				;my attempt at accessing sent count
				rx_count=PeekByte(ses\tcp_recbank,0)
				Print"rx_count is:"+rx_count
			
				ses\status=12 ; well time to reply this packet next round :D
			
			End If
		
		Case 12 ; Well time to reply a packet.
		
			;First we fill it upp with 0
			For i=0 To (max_bank-1)
				;PokeByte ses\tcp_sendbank,i,Rnd(255)
				PokeByte ses\tcp_sendbank,i,Rnd(255)
			Next
			
			

			rx_count=PeekByte(ses\tcp_recbank,0)
			
			;client_count=PeekByte(ses\tcp_recbank,0)
			PokeByte ses\tcp_sendbank,0,global_client_count
			PokeByte ses\tcp_sendbank,1,rx_count
			Print " sent back a rx_count of:"+rx_count

			
			;Secondly we reply it kindly.
			s=WriteBytes (ses\tcp_sendbank,ses\link,0,max_bank)
			;Print "Succesfull sending "+s+" bytes of data"
			 packetssent= packetssent+1
	
	
			ses\status=10 ; Well we cant wait for next coll packet to arive :D"
			
		End Select
	
	
	Next	
	
	ms=MilliSecs()-oldms
	If ms>msmax Then msmax=ms
	If ms<msmin Then msmin=ms
	count=count+1
	cmsmed=cmsmed+ms
	msmed=cmsmed/count   ; medium millisecs
	
	
	tick=tick+1
	If tick>=500 Then Print "Ticks: "+count+" MS="+ms+" MIN="+msmin+" MED="+msmed+" MAX="+msmax+ "Packets sent "+ packetssent : tick=0

	
	If KeyHit(19) Then MSMIN=99999 : msmed=0 : count=0 : msmax=0 : packetssent=0 :cmsmed=0: Print "Counter resets."

	Delay 10 ; this gives cpu time to rest of OS in windows. as server is not so cpu intensive.

Wend
;---------------------------------------------------------------------
;  functions
;---------------------------------------------------------------------



Function fn_delete_file(numberin)
	Print "Deleting File: "+numberin
	del_file_name$="file_dir/"+numberin+".ini"
	DeleteFile (del_file_name$)
	Print "File Deleted"	
End Function


Function fn_create_file(numberin)

	BestName$="Mark"
	;BestScore$="123"
	;BestLevel$="One and only"

	Print "Ganna create a text file with this:"+numberin+" identity."
	
	;file_name$(file_count)="file_dir/"+file_count+"_"+numberin+".ini"
	;got rid of file count prefix string manip hassle
	file_name$(file_count)="file_dir/"+numberin+".ini"
	Print file_name$(file_count)
	writethis$=file_name$(file_count)
	file_count=file_count+1
	
	; Open a file to write to 
	fileout = WriteFile(writethis$)
	Print"-------------------------------------"
	Print"fileout is:"+writethis$
	Print"-------------------------------------"
	; Write the information to the file 
	WriteString( fileout, BestName$ ) 
	;WriteInt( fileout, BestScore$ ) 
	;WriteByte( fileout, BestLevel$ ) 
	
	Print "Wrote to:"+writethis$

	; Close the file 
	CloseFile( fileout ) 
	
End Function







Client:


;------------ Client part ------------------------------
; this file needs to be saved as:
;
; client_v2.exe
;
; for VB.net front end to locate


; this is a dumb client.. it only spams server :D

max_bank = 512
sent_count=0


tcp_sendbank=CreateBank(max_bank)
tcp_recbank=CreateBank(max_bank)

;link=OpenTCPStream("www.tiberion.com",7056)
link=OpenTCPStream("127.0.0.1",7056)			;NOTE:  might need to replace with your IP info

If Not link Then Print "failed to create link." : Delay 3000 : End

Print "Connected.. let the spam flood."

status=12; we emulate a logged in client

While Not KeyHit(1)

	If Eof(link) Then Print "What server died ??? why   WHYYY !!?? " : Delay 5000 : End 


	Select status
	
	Case 10
	
		If ReadAvail(link)>=max_bank
		
			;time to read some ;)
			r=ReadBytes(tcp_recbank,link,0,max_bank)
			Print "have readin "+r+" bytes from server."
			Print "-----------------------------------------------------"
			;my attempt at accessing sent count
				xth=PeekByte(tcp_recbank,0)
				serv_count=PeekByte(tcp_recbank,1)
				Print"client count is:"+xth
				
			Print "Server reckons there is "+xth+" clients connected......"
			Print "Server thinks this clients sent him: "+serv_count+" packets of 512 bytes"
			Print "------------------------------------------------------"
			status=12 ; Yeppp time to respond... 
		End If
			
	
	Case 12
	
		;haha client time to spam server first we make a cool tcp packet with random nunbers.
		For i=0 To (max_bank-1)
			PokeByte tcp_sendbank,i,Rnd(255)
			;Print "filled 512 bytes with randz, bar first one"
			If sentcount<255
			PokeByte tcp_sendbank,0,sent_count
			Else sentcount=255
			EndIf
		Next
		
		;well we got our important randomnes.. time ti send the junk spam to server.
		s=WriteBytes (tcp_sendbank,link,0,max_bank)
		;Print "Sending "+s+" bytes to server."+sent_count+" times"
		sent_count=sent_count+1
		
		status=10  ; Well we go out and wait for packet :D
		
	
	End Select
	
		tick=tick+1
	If tick>=500 Then Print CurrentTime()+"...tick..." : tick=0



	;Delay 10 ; yep we have to delay some here to emulate many clients.. or cpu dies.
    Delay 500  ; MG Delay
Wend




Hope this helps someone.....

Updated the Server and client code, the client code now sends move requests to the server. The server holds the master copy of where the clients are (x and y co-ords). The server sends out positional data of all clients to all clients.

new code does this:




The new client code sends out move requests to the server after a few iterations. If you start different clients a few seconds apart you will see the move requests being recieved by the server, the server updates the x and y co-ords of the client.... the rest is history.


You might want to drop the delay (set at 1200 = 1.2 secs).....

Server:

; TCP engine ULTRA FAST
;
; Written initially by Daniel Eriksson  (daniel@...)

; added to by M Gormley, also incorporated
; a VB.net front end which can be used to start
; the server, start clients, monitor how many clients
; are running, kill the server and cleanup files




;VARS------------------------------------------------------------

Dim player_data(512)  ;512 bytes to copy into each clients
                       ;stuff

;Populate dummy player data
For count = 10 To 490 Step 20
player_data(count+1)=player_number
player_data(count+2)=count				;x
player_data(count+3)=count				;y
player_data(count+4)=0					; 0 bullet dead, 1 alive
player_data(count+5)=count+10			;bullet x
player_data(count+6)=count+10			;bullet y

	    ;          player count:  1 byte	
		;          player: x, y co -ords, 2 bytes
		;          shot anything:  yes/no 1 byte
		;          projectile alive: 1 byte
		;          projectile x,y: 2 bytes
		;          player world count:  1 byte
		;          leaving 2 bytes for whatever 
Next


max_bank=512
global_client_count=0
Dim file_name$(255); 255 possible clients - who'd need more?
Global file_count=0


Type session

	Field link
	Field tcp_sendbank
	Field tcp_recbank
	Field status
	Field player_number

End Type

;window=CreateWindow("Key press me window",100,100,640,200,0,1)  BBasic
Graphics 400,500,16,2            ; B3D

server=CreateTCPServer(7056)
Print "server is running.."

msmin=9999999 ; minimums millisecs :D

While Not KeyHit(1)   ;Hehe this command dosent work in BlitzPluss with the console window.

	stream = AcceptTCPStream(server)
	If stream
		global_client_count=global_client_count+1
		Print "New stream detected. memory allocated."
		ses.session = New session
		ses\link=stream
		ses\tcp_sendbank = CreateBank(max_bank)	
		ses\tcp_recbank = CreateBank(max_bank)
		ses\status =10 ; Simulate login.
		;ses\client_count=global_client_count
		
		ses\player_number=global_client_count
		
		fn_create_file(Int ses\link)
	
	End If


	oldms=MilliSecs()
	;Validate streams.. 
	For ses.session = Each session
	
		If Eof(ses\link) 
			Print "A session called "+ses\link+" has stop working."
			Print "Frees memory banks for session "+ses\link
			FreeBank ses\tcp_sendbank 
			FreeBank ses\tcp_recbank
			Print "deletes sessions "+ses\link
			
			numberin=ses\link
			fn_delete_file(Int ses\link)
			
			Delete ses
			global_client_count=global_client_count-1
		End If
		
	Next
	
	
	For ses.session = Each session
	
	
		Select ses\status
		Case 10
		
			If ReadAvail(ses\link)>=max_bank
			
				;so we got a new packet :D and its all 100% secure... so we can go on live our lifes
				r=ReadBytes (ses\tcp_recbank,ses\link,0,max_bank)
				Print "for session "+ses\link+" who has a tcp recbank of:"+ses\tcp_recbank
				Print "read "+r+" bytes from stream"
				
				;my attempt at accessing sent count
				rx_count=PeekByte(ses\tcp_recbank,0)
				Print"rx_count is:"+rx_count
				
				If PeekByte(ses\tcp_recbank,1)>0
					Print "Detected Move request for x of client:"+ses\tcp_recbank
					;works to here:  now problem is how to identify where this
					;client into the server is within the player_data array..... ?
					;answer must lie in writing the player_count once only to the
					;server data player number....cool
						
				EndIf
				
				Print "The server knows this is player number: "+ses\player_number
				xloc=(20*ses\player_number)-9
				player_data(xloc)=player_data(xloc)+1
				
				If PeekByte(ses\tcp_recbank,2)>0
					Print "Detected Move request for y of client:"+ses\tcp_recbank
				yloc=(20*ses\player_number)-8
				player_data(yloc)=player_data(yloc)+1	
				EndIf


			
				ses\status=12 ; well time to reply this packet next round :D
			
			End If
		
		Case 12 ; Well time to reply a packet.
		
			;First we fill it upp with 0
			For i=0 To (max_bank-1)
				;PokeByte ses\tcp_sendbank,i,Rnd(255)
				PokeByte ses\tcp_sendbank,i,0
			Next
			
			

			rx_count=PeekByte(ses\tcp_recbank,0)
			
			;client_count=PeekByte(ses\tcp_recbank,0)
			PokeByte ses\tcp_sendbank,0,global_client_count   ; way to tell client how many
			
															  ;  have been connected to the server
															  ;  another flag to say if player
															  ;  /client is alive or not
			
			 
			                                                  ; players are connected to server
			                                                  ; which will in turn let client
			                                                  ; know how much 
			PokeByte ses\tcp_sendbank,1,rx_count
			Print " sent back a rx_count of:"+rx_count
			
			;first 10 bytes for storing server stuff, then bytes 10 to 490
			; for player data
			;
			For count = 10 To 490
				PokeByte ses\tcp_sendbank,count,player_data(count); copying in data
			Next
			

			
			;Secondly we reply it kindly.
			s=WriteBytes (ses\tcp_sendbank,ses\link,0,max_bank)
			;Print "Succesfull sending "+s+" bytes of data"
			 packetssent= packetssent+1
	
	
			ses\status=10 ; Well we cant wait for next coll packet to arive :D"
			
		End Select
	
	
	Next	
	
	ms=MilliSecs()-oldms
	If ms>msmax Then msmax=ms
	If ms<msmin Then msmin=ms
	count=count+1
	cmsmed=cmsmed+ms
	msmed=cmsmed/count   ; medium millisecs
	
	
	tick=tick+1
	If tick>=500 Then Print "Ticks: "+count+" MS="+ms+" MIN="+msmin+" MED="+msmed+" MAX="+msmax+ "Packets sent "+ packetssent : tick=0

	
	If KeyHit(19) Then MSMIN=99999 : msmed=0 : count=0 : msmax=0 : packetssent=0 :cmsmed=0: Print "Counter resets."

	Delay 10 ; this gives cpu time to rest of OS in windows. as server is not so cpu intensive.

Wend
;---------------------------------------------------------------------
;  functions
;---------------------------------------------------------------------



Function fn_delete_file(numberin)
	Print "Deleting File: "+numberin
	del_file_name$="file_dir/"+numberin+".ini"
	DeleteFile (del_file_name$)
	Print "File Deleted"	
End Function


Function fn_create_file(numberin)

	BestName$="Mark"
	;BestScore$="123"
	;BestLevel$="One and only"

	Print "Ganna create a text file with this:"+numberin+" identity."
	
	;file_name$(file_count)="file_dir/"+file_count+"_"+numberin+".ini"
	;got rid of file count prefix string manip hassle
	file_name$(file_count)="file_dir/"+numberin+".ini"
	Print file_name$(file_count)
	writethis$=file_name$(file_count)
	file_count=file_count+1
	
	; Open a file to write to 
	fileout = WriteFile(writethis$)
	Print"-------------------------------------"
	Print"fileout is:"+writethis$
	Print"-------------------------------------"
	; Write the information to the file 
	;WriteString( fileout, BestName$ )       writing a string from above results 
	;                                        in some corruption to the file.....
	
	WriteString( fileout, "new string:1" ) 
	;WriteInt( fileout, BestScore$ ) 
	;WriteByte( fileout, BestLevel$ ) 
	
	Print "Wrote to:"+writethis$

	; Close the file 
	CloseFile( fileout ) 
	
End Function









;------------ Client part ------------------------------
; this file needs to be saved as:
;
; client_v2.exe
;
; for VB.net front end to locate

; this is a client that sends move requests to server after the test_x_move has elapsed
;  excuse the code formatting, but it does work........

max_bank = 512
sent_count=0

Dim srv_player_data(512);  place to store what the server reckons state of play is

test_x_move=20;   amount of packets to have sent before start adjusting x co-ord of this player
test_y_move=7;    amount of packets to have sent before start adjusting y co-ord of this player
x_move=0
y_move=0


tcp_sendbank=CreateBank(max_bank)
tcp_recbank=CreateBank(max_bank)

;link=OpenTCPStream("www.tiberion.com",7056)
link=OpenTCPStream("127.0.0.1",7056)			;NOTE:  might need to replace with your IP info

Graphics 400,700,16,2            ; B3D

If Not link Then Print "failed to create link." : Delay 3000 : End

Print "Connected.. This player is Alive in the world...."

status=12; we emulate a logged in client

While Not KeyHit(1)

	If Eof(link) Then Print "What server died ??? why   WHYYY !!?? " : Delay 5000 : End 


	Select status
	
	Case 10
	
		If ReadAvail(link)>=max_bank
		
			;time to read some ;)
			r=ReadBytes(tcp_recbank,link,0,max_bank)
			Print "have readin "+r+" bytes from server."
			Print "-----------------------------------------------------"
			;my attempt at accessing sent count
				xth=PeekByte(tcp_recbank,0)
				serv_count=PeekByte(tcp_recbank,1)
				Print"client count is:"+xth
				
		    ;attempt at copying in data received from server now
		    For copy_ct=1 To 511
		    srv_player_data(copy_ct)=PeekByte(tcp_recbank,copy_ct)
		    Next
			
			;current players
			mem_loc=((20*1)-10)
			Print "This player has sent "+srv_player_data(1)+" packets"
			For loop = 1 To xth
	            ;work out where in 512 bytes this players x and y co-ords are:		
			    mem_loc=((20*loop)-10)
			    Print"mem_loc is:"+mem_loc
			    
				Print "player: "+loop+" x co-ord:"+srv_player_data(mem_loc+1)
				Print "player: "+loop+" y co-ord:"+srv_player_data(mem_loc+2)
			Next	
			
			
			status=12 ; Yeppp time to respond... 
		End If
			
	
	Case 12
	

	
	    ;          player count:  1 byte	
		;          player: x, y co -ords, 2 bytes
		;          shot anything:  yes/no 1 byte
		;          projectile alive: 1 byte
		;          projectile x,y: 2 bytes
		;          player world count:  1 byte
		;          leaving 2 bytes for whatever       
	
	
	    ;byte 1: 1, add 1 to x,2 subtract 1 from x
	    ;byte 2: 1, add 1 to y,2 subtract 1 from y
	
		;haha client time to spam server first we make a cool tcp packet with random nunbers.
		For i=0 To (max_bank-1)
			PokeByte tcp_sendbank,i,0
			If sentcount<255
			PokeByte tcp_sendbank,0,sent_count
			Else sentcount=255
			EndIf
		Next
		
		If x_move>test_x_move Then
		    Print"set x___________________________________ to move"
			PokeByte tcp_sendbank,1,1		;1 here means server needs to move x for this
			                                ;player/client by +1

		End If
		If y_move>test_y_move Then
		    Print"set y___________________________________ to move"
			PokeByte tcp_sendbank,2,1       ;1 here means server needs to move y for this
			                                ;player/client by +1

		End If

		s=WriteBytes (tcp_sendbank,link,0,max_bank)
		;Print "Sending "+s+" bytes to server."+sent_count+" times"
		sent_count=sent_count+1
		
		status=10  ; Well we go out and wait for packet :D
		
	
	End Select
	
		tick=tick+1
	If tick>=500 Then Print CurrentTime()+"...tick..." : tick=0
	
	Print "First 8 bytes of srv_player_data"
	;For ct=10 To 70 Step 20
	For ct=10 To 50 Step 20
	play_ct=play_ct+1
	

	  ;Print "Player:"+play_ct+"  srv_player_data is:"+srv_player_data(ct)
	  ;Print "Player:"+play_ct+"  srv_player_data is:"+srv_player_data(ct+1)
	  ;Print "Player:"+play_ct+"  srv_player_data is:"+srv_player_data(ct+2)
	  ;Print "Player:"+play_ct+"  srv_player_data is:"+srv_player_data(ct+3)
	  ;Print "srv_player_data is:"+srv_player_data(ct+4)
	  ;Print "srv_player_data is:"+srv_player_data(ct+5)
	  ;Print "srv_player_data is:"+srv_player_data(ct+6)
	  ;Print "---------------end data:"+ct+" ----------"
	Next
	
	play_ct=0

    ;update x and y co-ords for this client to send to server:-	
	x_move = x_move+1
	y_move = y_move+1

	;Delay 10 ; yep we have to delay some here to emulate many clients.. or cpu dies.
    Delay 1700  ; MG Delay, make this smaller again once tired of debug.....
Wend





;  



One way to cope with even more clients.. is to have a server que. that way server will only send some packets at a certain time. and it will kep the ISP happy :D

i have done this in my little rpg game.
so important packet arrive first. and broadcast then there is send time. a little like old fasion TimeSpace.

Hmm a server queue, might invest this more once ratify my 3d JV-ODE blah end zone truckin headache. Am using a vastly modified version of your ultrafast server Wings. thanks again, see here:
http://www.blitzbasic.com/Community/posts.php?topic=72220#864502

basic i store tcpip packet in a type and data in memmory bank.

i se that there is even flow on tcp sending..


this way one have controll over how much data that can be sent over stream. it takes planning..

Moved my game forwards a little, the code is nowhere near ready for public consumption, maybe it never will be - two trucks alive in my 3D arena which are clients to a server provided in the first instance by WINGS, modified a bit to take it to this. Wings has provided me with some more good advice that I've still to implement but all in good time.

I plan to have a new front end that will attempt to source the IP address of the client prior to executing the B3D code, maybe some logic to source the IP address of the server..... soon.