UDP questions

BlitzMax Forums/BlitzMax Programming/UDP questions

UDP is much simpler than TCP, but I can't seem to find a good example of it.

UDP is connectionless. It only sends data to an IP address. So I don't understand why so many UDP examples use ConnectSocket(), especially when the docs themselves say ConnectSocket() is for TCP sockets only.

What I really want is something like this:

socket:TSocket=CreateUDPSocket()
BindSocket(socket,80)
socket.send ip$,port:int,data:byte ptr,size:int

So how is this done?

UDP is faster than TCP but I wouldn't say its simpler.

You can't guarantee that UDP packets will arrive in the right order, and that's if they arrive at all. You don't have to worry about that with TCP.

Just my $0.02. I'd like to see some examples of how to use UDP correctly, too. I'm no expert.

It's simpler because there is no connection. You just say "Send this data to this IP address and port". Yet no one seems to have a clue how to do that.

Not sure what sort of example you're after but does this and/or this help?
Namely Yan's code ..
Strict

Framework BRL.Basic
Import BRL.socket
Import BRL.standardio

Local socket:TSocket = CreateUDPSocket()

If socket = Null Then RuntimeError "Couldn't create UDP socket"

SWriteLine(socket, "83.149.87.203", 7778, "\info")

Local info$ = SRead$(socket, "83.149.87.203", 7778)

Print info.length + " : " + info$

socket.Close()

End


Function SRead$(socket:TSocket, host$, port, bufferSize=1024)
	Local buf:Byte[bufferSize], rip, rport  
	Local receivedLen, time = MilliSecs()
	
	Repeat
		receivedLen = 0
		Local read = socket._socket
		If socket.Connected()
			Local size = socket.ReadAvail()
			If size
				receivedLen = recvfrom_(socket._socket, buf, size, 0, rip, rport)
				If (rip = HostIp(host$)) And (rport = port) Then Exit
			EndIf
		EndIf	
	Until (MilliSecs() - time) >= 30000
	
	If receivedLen > 0 Then Return String.FromBytes(buf, receivedLen)
End Function	

Function SWriteLine(socket:TSocket, host$, port, str$)
	Local buf:Byte Ptr = (str$ + "~r~n").ToCString()
	Local sent = sendto_(socket._socket, buf, str.length + 2, 0, HostIp(host$), port)

	MemFree buf
	
	Return sent
End Function

and Ghislain's code (based from the same)...
Strict

Local socket:TSocket = CreateUDPSocket()
If socket = Null Then RuntimeError "Couldn't create UDP socket"

' Listen to the port!
BindSocket(socket, 8080)

' This isn't required..
' ConnectSocket(socket, HostIp("127.0.0.1"), 8080)

' This seems to be always true..
' If SocketConnected(socket) Then Print "Socket connected."

' Returns 0.0.0.0 : 0
' Print DottedIP(SocketRemoteIP(socket)) + " : " + SocketRemotePort(socket)

Local counter:Int = 0
Local l:Int = 0

While Not KeyDown(key_escape)
	l = SocketReadAvail(socket)
	
	If l
		counter = counter + 1
		Print "Avail: " + l + " bytes."
		Print "Data: " + sRead(socket)
	End If
	
	If counter > 10 Then Exit
Wend

CloseSocket(socket)
End

' ---------------------------------

' This is borrowed from 'Yan'..
Function sRead:String (socket:TSocket)
	Local buf:Byte[1024]
	Local receivedLen = socket.Recv(buf, 1024)
	Return String.FromBytes(buf, receivedLen)
End Function


Try looking for previous threads in which I've written about `UDP`, I am sure there was one where we talked about this at some length in figuring out how to do it.

SWriteLine(socket, "83.149.87.203", 7778, "\info")
That is close, but I want to send raw data, not text.

That is close, but I want to send raw data, not text.
Seriously? You can't figure that out for yourself?

No, I do not have a magic book of undocumented BlitzMax commands. "SWriteLine" isn't highlighted in the IDE, and "SWriteBytes" won't compile.

'Be sure to import pub.stdc for the strlen function to be identified, or take a size parameter

Function SWriteBytes:Int(socket:TSocket, host$, port, data:Byte Ptr)
	Local sent:Int = sendto_(socket._socket, data, _strlen(data), 0, HostIp(host$), port)
	
	Return sent
	
End Function


Extern
	Function _strlen:Int(s:Byte Ptr) = "strlen"
	
End Extern


oh, i see it now.

Cool, I think this is everything I need. Thanks.

Here is an easy UDP networking class:
http://blitzmax.com/codearcs/codearcs.php?code=2325

Vertex.BNetEx would have solved most of that questions and problems upfront ... and will solve many problems your class ignores and into which you will run pretty fast if you try to use it under real circumstances.

Nice start thought, thanks for sharing :)

All I found about BNet is a forum thread that hasn't been active in 5 months and a website in German.

http://vertex.dreamfall.at/projects.php

There is a simple udp example in the zip. It has been updated several times and still is supported. ... it is in german but nothing too complex that can't be understood by looking at the code.

The code seems pretty simple. What does this specifically support?

Lots of stuff.. You can get the info for your network card (MAC address, device name etc), UDP and TCP support (write lines/bytes/ints/floats.. etc; for protocols), cross-platform, ping ip/site..

Does his pinging work without requiring the other client be programmed to respond to the ping request? Can it just ping an IP address, or does it send a message saying "Send me a message back"? It would be easier if it was possible to ping an IP address without requiring the other running program to send a response.

Not sure, from all I can tell it does not.

I think a multithreaded module that continually processes messages is the right way to do this.

This is a simple UDP code i found that works :D

<code>
Strict

' one for reading
Local udpRead:tSocket = CreateUDPSocket()
BindSocket (udpRead, 49000)

' one for writing
Local udpWrite:tSocket = CreateUDPSocket()
ConnectSocket (udpWrite, HostIp ("127.0.0.1"), 49000)

' Send some data
Local b:Byte [] = [Byte(9), Byte(7), Byte(5), Byte(3), Byte(1)]
UdpWrite.send (Varptr b[0], b.length)

' create a loop which waits for some data
While True

If SocketReadAvail (UdpRead)
' a bank to store the input
Local tmpBank:TBank = CreateBank (1024)
' size of data-package
Local length:Int = UdpRead.recv (BankBuf (tmpBank), tmpBank.size() )
' print data
For Local i:Int = 0 To length - 1
Print tmpBank.PeekByte(i)
Next
' exit this loop
Exit
End If

Wend


CloseSocket (udpWrite)
CloseSocket (udpRead)
End
</code>

origirnal post:

http://blitzbasic.com/Community/posts.php?topic=75694

Why do you not allocate the bank based on the size of the data waiting?

Something like this?
While True

	size = SocketReadAvail (UdpRead)
	if size > 0 then 
		' a bank to store the input
		Local tmpBank:TBank = CreateBank (size)
		' size of data-package
		Local length:Int = UdpRead.recv (BankBuf (tmpBank), size )
		' print data
		For Local i:Int = 0 To length - 1
			Print tmpBank.PeekByte(i)
		Next
		' exit this loop
		Exit
	End If

Wend