Thank you so much! Binding to the port is fine (and needed for client to get
past the NAT routers that 99% of end-users sit behind).
But binding to a specific address, such as the loopback/localhost (127.0.0.1)
forces it to an interface that has no route to the destination address. Makes
sense. In fact, I used to be a IP network engineer by trade. Kind of
embarrassing that I didn't see a basic routing problem. :)
The runtime error is awfully generic though. It should have said something like
"No route to host" or something descriptive.
Anyway, leaving the "from" address off fixed it.
For the curious, here is my basic two-way UDP client proof-of-concept. This one
is async, uses the select method, and allows one to pass in the server address
by command-line.
import asyncdispatch, asyncnet, os
import std/[net, selectors, strformat, strutils]
const
cfgMaxPacket = 508
serverPort = 9900
if paramCount() == 0:
echo "pass a server address"
quit()
let serverHost = paramStr(1)
proc showMessage(message: string) =
let parts = message.split("\n")
for part in parts:
echo "< " & part
proc doit() {.async.} =
let
socket = newAsyncSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
events = newSelector[int]()
events.registerHandle(socket.getFd, {Read}, 0)
events.registerHandle(0, {Read}, 0) # stdin
echo &"Listening to stdin and transmitting to {serverHost}:{serverPort}"
while true:
for got in events.select(-1):
if got.fd == socket.getFd().int:
var msgDetails = await socket.recvFrom(cfgMaxPacket)
let message = msgDetails.data
showMessage(message.strip)
elif got.fd == 0:
try:
await socket.sendTo(serverHost, Port(serverPort),
stdin.readLine())
except EOFError:
quit()
asyncCheck doit()
runForever()
Run