UDP based lossless (optional) network engine. I'd appreciate if you could test it.
About server: Every stream has it's own UDP port. First, client connects to server and then server will automatically redirect it to a new port.
I tested 22'000 packets in a row and it had no errors.
Functions:
server% = CreateUDPServer%([port%])
stream% = AcceptUDPStream%(server%)
stream% = OpenUDPStream%(ip$, port%, [localport%])
inip_from% = ReceiveUDPMsg%(stream%) - 0 if no message has arrived
result% = WriteUDPByte%(stream%, value%)
result% = WriteUDPBytes%(bank%, stream%, offset%, count%)
result% = WriteUDPLine%(stream%, txt$)
result% = WriteUDPInt%(stream%, value%)
result% = WriteUDPString%(stream%, txt$)
value% = ReadUDPByte%(stream%)
value% = ReadUDPBytes%(bank%, stream%, offset%, count%)
value% = ReadUDPLine$(stream%)
value% = ReadUDPInt%(stream%)
value% = ReadUDPString$(stream%)
remote_port% = UDPPort%(stream%)
remote_intip% = UDPIP%(stream%)
byte_count% = UDPReadAvail%(stream%)
RemoveUDPStream%(stream%)
Source:
Const UDPResponseDelay% = 2000, UDPRetries% = 5, LossLessUDP% = True
Function CreateUDPServer%(port% = 0)
Local server% = CreateUDPStream(port%), bank%
If server%
bank% = CreateBank(4 * 3 + 1)
PokeInt bank%, 0 * 4, server%
PokeInt bank%, 1 * 4, UDPStreamIP(server%)
PokeInt bank%, 2 * 4, UDPStreamPort(server%)
PokeByte bank%, 3 * 4, 1
Return bank%
EndIf
End Function
Function AcceptUDPStream%(bank%)
Local accepted%
Local server% = PeekInt(bank%, 0 * 4)
Local ip% = PeekInt(bank%, 1 * 4)
Local port% = PeekInt(bank%, 2 * 4)
Local from% = RecvUDPMsg(server%)
If from%
clientip% = UDPMsgIP(server%)
clientport% = UDPMsgPort(server%)
value% = ReadInt(server%)
If value% => 12345 And value% =< 23456 Then
; Create stream bank
bank% = CreateBank(4 * 3 + 1)
accepted% = CreateUDPStream()
PokeInt bank%, 0, accepted%
PokeInt bank%, 4, clientip%
PokeInt bank%, 8, clientport%
PokeByte bank%, 12, 0
WriteInt accepted%, UDPStreamPort(accepted%)
SendUDPMsg accepted%, clientip%, clientport%
Return bank%
Else
FreeBank bank%
CloseUDPStream accepted%
Return False
EndIf
EndIf
End Function
Function OpenUDPStream%(ip$, port%, localport% = 0)
Local stream% = CreateUDPStream(localport%)
Local bank% = CreateBank(4 * 3 + 1)
PokeInt bank%, 0, stream%
PokeInt bank%, 4, IntIP(ip$)
PokeInt bank%, 8, port%
PokeByte bank%, 12, 1
validation% = Rand(12345, 23456)
WriteInt stream%, validation%
SendUDPMsg stream%, PeekInt(bank%, 4), PeekInt(bank%, 8)
For i = 1 To UDPRetries%
tim% = MilliSecs()
Repeat
from% = RecvUDPMsg(stream%)
Until from% Or MilliSecs() - tim% > UDPResponseDelay%
If from%
value% = ReadInt(stream%)
PokeInt bank%, 8, value%
Return bank%
EndIf
Next
; Failed
FreeBank bank%
CloseUDPStream stream%
Return False
End Function
Function ReceiveUDPMsg%(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
from% = RecvUDPMsg(stream%)
If from%
If UDPMsgIP(stream%) = ip% And UDPMsgPort(stream%) = port%
index% = ReadByte(stream%)
If LossLessUDP%
If Not index% = msgindex%
; Response to message
PokeByte bank%, 12, index%
WriteByte stream%, index%
SendUDPMsg stream%, ip%, port%
Return from%
Else
DebugLog "Invalid message index!"
; Message already received
WriteByte stream%, index%
SendUDPMsg stream%, ip%, port%
Return False
EndIf
Else
Return from%
EndIf
EndIf
EndIf
End Function
Function WriteUDPByte%(bank%, value%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
For i = 1 To UDPRetries%
; Send message
WriteByte stream%, msgindex%
WriteByte stream%, value%
SendUDPMsg stream%, ip%, port%
If WaitUDPResponse(bank%) Then Return True
Next
End Function
Function ReadUDPByte%(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
Return ReadByte(stream%)
End Function
Function WriteUDPBytes%(from%, bank%, offset%, count%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
For i = 1 To UDPRetries%
; Send message
WriteByte stream%, msgindex%
WriteBytes from%, stream%, offset%, count%
SendUDPMsg stream%, ip%, port%
If WaitUDPResponse(bank%) Then Return True
Next
End Function
Function ReadUDPBytes%(from%, bank%, offset%, count%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
Return ReadBytes(from%, stream%, offset%, count%)
End Function
Function WriteUDPInt%(bank%, value%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
For i = 1 To UDPRetries%
; Send message
WriteByte stream%, msgindex%
WriteInt stream%, value%
SendUDPMsg stream%, ip%, port%
If WaitUDPResponse(bank%) Then Return True
Next
End Function
Function ReadUDPInt%(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
Return ReadInt(stream%)
End Function
Function WriteUDPString%(bank%, txt$)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
For i = 1 To UDPRetries%
; Send message
WriteByte stream%, msgindex%
WriteString stream%, txt$
SendUDPMsg stream%, ip%, port%
If WaitUDPResponse(bank%) Then Return True
Next
End Function
Function ReadUDPString$(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
Return ReadString(stream%)
End Function
Function WriteUDPLine%(bank%, txt$)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
For i = 1 To UDPRetries%
; Send message
WriteByte stream%, msgindex%
WriteLine stream%, txt$
SendUDPMsg stream%, ip%, port%
If WaitUDPResponse(bank%) Then Return True
Next
End Function
Function ReadUDPLine$(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
Return ReadLine(stream%)
End Function
Function UDPPort%(bank%)
Return PeekInt(bank%, 2 * 4)
End Function
Function UDPIP%(bank%)
Return PeekInt(bank%, 1 * 4)
End Function
Function UDPReadAvail%(bank%)
Return ReadAvail(PeekInt(bank%, 0 * 4))
End Function
Function RemoveUDPStream%(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
CloseUDPStream stream%
FreeBank bank%
End Function
; NON-USER COMMANDS --------------------------------------------------------------------------------
Function WaitUDPResponse%(bank%)
Local stream% = PeekInt(bank%, 0)
Local ip% = PeekInt(bank%, 4)
Local port% = PeekInt(bank%, 8)
Local msgindex% = PeekByte(bank%, 12)
If LossLessUDP%
; Wait for replay
tim% = MilliSecs()
Repeat
from% = RecvUDPMsg(stream%)
Until from% Or MilliSecs() - tim% > UDPResponseDelay%
If from%
If UDPMsgIP(stream%) = ip% And UDPMsgPort(stream%) = port%
; Message from same client
index% = ReadByte(stream%)
If index% = msgindex%
If msgindex% < 250 Then PokeByte bank%, 12, msgindex% + 1 Else PokeByte bank%, 12, msgindex% - 250
Return True
EndIf
EndIf
EndIf
Else
Return True
EndIf
End Function
Function IntIP(ip$)
Local a = UDPSector$(ip$, ".", 0)
Local b = UDPSector$(ip$, ".", 1)
Local c = UDPSector$(ip$, ".", 2)
Local d = UDPSector$(ip$, ".", 3)
Return (a Shl 24) + (b Shl 16) + (c Shl 8) + d
End Function
Function UDPSector$(txt$, separator$, sector%, toend% = False)
Local result$ = "", occ
For i = 1 To Len(txt$)
If Mid$(txt$, i, 1) = separator$
occ = occ + 1
If toend% And occ% > sector% Then result$ = result$ + Mid$(txt$, i, 1)
Else
If occ => sector Then result$ = result$ + Mid$(txt$, i, 1)
EndIf
If Not toend% Then If occ > sector Then Exit
Next
Return result$
End Function
Function UDPSectors%(txt$, needle$)
occ% = 0
For i = 1 To Len(txt$) Step 1
If Instr(txt$, needle$, i)
occ% = occ% + 1
i = Instr(txt$, needle$, i)
Else
Exit
EndIf
Next
Return occ%
End Function
Example:
; ------------Server--------------
Include "udp.bb"
Print "Creating UDP server..."
server% = CreateUDPServer(2010)
If server%
Print "Waiting for client..."
Repeat
stream% = AcceptUDPStream(server%)
Until stream%
Print "Client (" + DottedIP(UDPIP(stream%)) + ":" + UDPPort(stream%) + ") connected!"
Repeat
If ReceiveUDPMsg%(stream%)
avail% = UDPReadAvail(stream%)
Print avail% + " bytes available!"
value$ = ReadUDPLine$(stream%)
Print "Message: " + value$
EndIf
Forever
Else
Print "Failed to create server!"
EndIf
WaitKey
; ------------Client--------------
Include "udp.bb"
Print "Connecting to server..."
stream% = OpenUDPStream("127.0.0.1", 2010)
If stream%
Print "Received access to " + DottedIP(UDPIP(stream%)) + ":" + UDPPort(stream%)
For i = 1 To 1000
msg$ = "Hello message #" + i + "!"
If WriteUDPLine(stream%, msg$)
Print "Message: " + msg$
EndIf
Next
Else
Print "Failed!"
EndIf
WaitKey
|