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.