Reading a string from the terminal is easy.
Receiving a UDP packet is easy and there are ready examples.
Sending a UDP packet is really easy.
So SURELY doing all three at once is also easy.... I just spent many days on
working out different ways to do that.
Fortunately since UDP is connectionless, it turns out a simple pair of threads
can do it; but this is very non-obvious at first. At least it wasn't to me
anyway.
I also got a version to sort of work with many layers asynchronous blah blah
blah working. It is about 300 lines line and isn't even slightly readable.
So, for any future UDP client and server writers, here is my very simplified
bidirectionial UDP client. Feel free to use as a simple starting point:
import net, threadpool, strutils
const MAX_PACKET_SIZE = 508
const clientAddr = "127.0.0.1"
const clientPort = 8800
const serverAddr = "127.0.0.1"
const serverPort = 9900
proc sendMessage(socket: Socket, message: string) =
socket.sendTo(serverAddr, Port(serverPort), message)
echo "sent: ", message
proc recvMessage(message: string) =
echo "received: ", message
proc onPacket(socket: Socket): string =
var incomingMessage = ""
var srcAddress = ""
var srcPort = Port(0)
let msgLen = socket.recvFrom(incomingMessage, MAX_PACKET_SIZE,
srcAddress, srcPort)
echo "packet of size $1 seen from $2:$3".format(msgLen, srcAddress,
srcPort)
return incomingMessage
let socket: Socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
socket.bindAddr(Port(clientPort), clientAddr)
var messageFlowVar = spawn stdin.readLine()
var packetFlowVar = spawn onPacket(socket)
while true:
if messageFlowVar.isReady():
sendMessage(socket, ^messageFlowVar)
messageFlowVar = spawn stdin.readLine()
if packetFlowVar.isReady():
recvMessage(^packetFlowVar)
packetFlowVar = spawn onPacket(socket)
Run
Feel free to convert the `if {}.isReady()` into while loops and then slip in a
`os.sleep(50)` to make it a tad easier on the CPU.
Next, I'll be trying to avoid pre-assigning the client address and port; but
instead capturing the OS-assigned outbound src port on first `sendTo` so that
the other server can consistently see the same client source port over time. If
nothing else, that will help with tracking firewall NAT passage. If anyone
knows an clean and easy way to do that, let me know.