Int + String in one UDP Message - Byte Ptr Prob?

BlitzMax Forums/BlitzMax Programming/Int + String in one UDP Message - Byte Ptr Prob?

Hi,

i have some problems with my UDP Transfer. My Server don't get a correct String. The Integers are just fine. It seems to be a Misstake at the Byte Pointers or so ...

Maybe anyone see my Misstake:

Server:
SuperStrict

' Create a UDP Socket
Local client:TSocket = CreateUDPSocket()

' Bind to Port for incomming Messages
If Not BindSocket(client, 8085) Then RuntimeError( "Unable to listen on port." )

' tmp Buffer - the Bytes that i got from UDP Socket
Local tmp:Byte Ptr[1024]

' The Variables (from client)
Local name:String
Local xpos:Int
Local ypos:Int

' Read all incomming messages
While True

	If SocketReadAvail(client) Then
		
		' print how many bytes arrived
		Local avail:Int = client.recv(tmp, 1024)
		Print (String(avail) + " Bytes available.")
		
		' first integer
		Print ("Name has "+String(Int(tmp[0]))+" Bytes")
		
		' second is my name string
		name.FromBytes(tmp[1], Int(tmp[0]))
		
		Print(name)
		
		' my location variables
		xpos = Int(tmp[2])
		ypos = Int(tmp[3])
		
		Print "got packet with: "+name+" xpos: "+String(xpos)+" ypos: "+String(ypos)
		
	Else
		Delay(500)
	EndIf

Wend

CloseSocket(client)
End


Client:
SuperStrict

' Create a UDP Socket
Local server:TSocket = CreateUDPSocket()

' Bind Socket to a Port (incomming Messages)
If Not BindSocket(server, 8086) Then RuntimeError("Unable to Bind Socket - Port 8086 maybe in use...")

' Connect to a IP and Port (outgoing Messages)
If Not ConnectSocket(server, HostIp("127.0.0.1"), 8085) Then RuntimeError "Couldn't connect to server"

' Player Name + x position + y position
Local name:String = "Player"
Local xpos:Int = 450
Local ypos:Int = 400

' Create Data Ptr to be send
Local data:Byte Ptr[4]
data[0] = Byte Ptr(name.length)
data[1] = Byte Ptr(name.ToCString())
data[2] = Byte Ptr(xpos)
data[3] = Byte Ptr(ypos)

' send data (int + string + int + int) / int = 4 byte
server.send(data, 4 + name.length + 4 + 4)

CloseSocket(server)
End


I'm very thankful for some hints :-)

I know this doesn't help your current problem, but..
data[1] = Byte Ptr(name.ToCString())

This is a memory leak.... unless you call MemFree on the byte ptr at some point.

FYI.

Actually, you are not sending the string anywhere.... only a byte ptr reference.

You will need to copy the characters into a byte stream and read those number of bytes out of the other end (using the length as the indicator to size of string) - ie. your data byte array will need to be longer than 4 bytes... you will need 3 + max string length...
This assumes that length, x and y are <= 255. Otherwise you will need more bytes for those too.

Okay, thanks for the hint :-)

i will try again and tell the results tomorrow :-)

Let's pretend you do in fact want to send :
Local name:String = "Player"
Local xpos:Int = 450
Local ypos:Int = 400

You will need at least.... 7 + 2 + 2 bytes to transfer using non-compressed stream.

If you don't include Length, you can get away with having a null-terminator (ascii-0) at the end of the string, then two bytes (a short) per coord.

Something perhaps like :
SuperStrict

Local name:String = "Player"
Local xpos:Int = 450
Local ypos:Int = 400


Local data:Byte[] = New Byte[11]
Local offset:Byte Ptr = data
For Local i:Int = 0 Until name.length
	offset[i] = name[i]
Next
offset:+ name.length + 1
Short Ptr(offset)[0] = xpos
offset:+2
Short Ptr(offset)[0] = ypos


For Local i:Int = 0 Until data.length
	Print data[i]
Next


Oh wow thanks for your work :-D

You might find it easier to work with a TBank while you are building your data to send, as it has functions for poking Byte, Short, Int, Long, Float, Double etc...

And be aware of Endian issues if you intend passing data between Intel and PPC systems.

I don't know if it would work any other way but if you are sendign bytes then it should be something like this (untested):
SuperStrict

' Create a UDP Socket
Local client:TSocket = CreateUDPSocket()

' Bind to Port for incomming Messages
If Not BindSocket(client, 8085) Then RuntimeError( "Unable to listen on port." )

' tmp Buffer - the Bytes that i got from UDP Socket
Local tmp:Byte Ptr[1024]

' The Variables (from client)
Local name:String
Local xpos:Int
Local ypos:Int

' Read all incomming messages
While True
	Local tmpptr:Byte Ptr
	If SocketReadAvail(client) Then
		
		' print how many bytes arrived
		Local avail:Int = client.recv(tmp, 1024)
		Print (String(avail) + " Bytes available.")
		tmpptr = tmp
		Local strl:Int = Int Ptr(tmpptr)[0]
		tmpptr:+4 
		' first integer
		name = ""
		For index;Int = 0 Until strl
			name:+ Chr(tmpptr[0])
			tmpptr:+1
		Next 
		Print ("Name has "+strl+" Bytes")
		Print(name)
		
		' my location variables
		xpos = Int Ptr(tmpptr)[0]
		tmpptr:+4
		ypos = Int Ptr(tmpptr)[0])
		
		Print "got packet with: "+name+" xpos: "+String(xpos)+" ypos: "+String(ypos)
		
	Else
		Delay(500)
	EndIf

Wend

CloseSocket(client)
End


Client:
SuperStrict

' Create a UDP Socket
Local server:TSocket = CreateUDPSocket()

' Bind Socket to a Port (incomming Messages)
If Not BindSocket(server, 8086) Then RuntimeError("Unable to Bind Socket - Port 8086 maybe in use...")

' Connect to a IP and Port (outgoing Messages)
If Not ConnectSocket(server, HostIp("127.0.0.1"), 8085) Then RuntimeError "Couldn't connect to server"

' Player Name + x position + y position
Local name:String = "Player"
Local xpos:Int = 450
Local ypos:Int = 400

' Create Data Ptr to be send
Local data:Byte Ptr[4+name.length+4+4] 'int(4 bytes) + string.length+ int(4 bytes)+int(4 bytes)
Local dataptr:byte ptr = data
Int Ptr(data)[0] = name.length
dataptr :+4
For Local n:Int = 0 Until name.length
	dataptr[0] = name[n]
	dataptr:+1
Next
Int Ptr(dataptr)[0] = xpos
dataptr:+4
Int Ptr(dataptr)[0] = ypos

' send data (int + string + int + int) / int = 4 byte
server.send(data, 4 + name.length + 4 + 4)

CloseSocket(server)
End

it should give you an idea

@Jesse
Hey yeah that works - thanks alot :-D

@Brucey
Thanks for the hints - i'll play around with TBanks :-)
Lucky that there is a ?PPC Command - will keep it in mind Thanks :-)

Hey, i got it working with TBank now :-)

Client:
SuperStrict

' Create a UDP Socket
Local server:TSocket = CreateUDPSocket()

' Bind Socket to a Port (incomming Messages)
If Not BindSocket(server, 8086) Then RuntimeError("Unable to Bind Socket - Port 8086 maybe in use...")

' Connect to a IP and Port (outgoing Messages)
If Not ConnectSocket(server, HostIp("127.0.0.1"), 8085) Then RuntimeError "Couldn't connect to server"

' Player Name + x position + y position
Local name:String = "Player"
Local xpos:Int = 450
Local ypos:Int = 400

Local bank:TBank = New TBank
Local data:TBankStream = CreateBankStream(bank)

data.WriteInt(name.length)
data.WriteString(name)
data.WriteInt(xpos)
data.WriteInt(ypos)

' send data (int + string + int + int) / int = 4 byte
server.send(BankBuf(bank), StreamSize(data))

CloseSocket(server)
End


Server:
SuperStrict

' Create a UDP Socket
Local client:TSocket = CreateUDPSocket()

' Bind to Port for incomming Messages
If Not BindSocket(client, 8085) Then RuntimeError( "Unable to listen on port." )

' tmp Buffer - the Bytes that i got from UDP Socket
Local tmp:Byte Ptr[1024]

Local bank:TBank = CreateBank(1024)
Local data:TBankStream = CreateBankStream(bank)

' The Variables (from client)
Local name:String
Local xpos:Int
Local ypos:Int

' Read all incomming messages
While True
	If SocketReadAvail(client) Then
		
		' print how many bytes arrived
		Local recieved:Int = client.recv(BankBuf(bank), 1024)
		Print (String(recieved) + " Bytes recieved.")

		Local strl:Int = data.ReadInt()
		
		Print "read: "+String(strl)
		
		name = data.ReadString(strl)

		' my location variables
		xpos = data.ReadInt()
		ypos = data.ReadInt()
				
		Print "got packet with: "+name+" xpos: "+String(xpos)+" ypos: "+String(ypos)

		SeekStream(data,0)
		
	Else
		Delay(500)
	EndIf

Wend

CloseSocket(client)
End


Maybe anyone can use or learn from this :-)

Thanks to Brucey and Jesse for Help and Hints :-)

[Edit]
Btw: I do have to watchout for Endian issues within TBanks ?

After it is done reading, don't forget to reset your pointer so it can read from the begging when new data is received:
SeekStream(data,0)


Nice Idea :-)

I updated the Post above.