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

Reply via email to