| 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
 
 |