Search code examples
socketsudpraku

How can a Raku UDP server know where to send a response to?


I can write a UDP server that will receive messages from a client using IO::Socket::Async

my $socket = IO::Socket::Async.bind-udp: 'localhost', 3333;

react whenever $socket.Supply: :bin {
    say "Received some junk: { .gist }";    
}

And I can send things to this server:

given IO::Socket::Async.udp {
    await .print-to: 'localhost', 3333, 'Hello';
}

But when I try to get the server to send back a message response, I realise I don't have the host and port to send it to. How can I get this information?

Normally, I think the answer to this would be to use recvfrom and pass a pointer to a sockaddr struct that will get populated with the address information of the incoming connection. But there seems to be no way to do this without reaching for NativeCall (and even then it's not clear to me how to do that).

Or am I missing something?


Solution

  • TL;DR The solution to your problem was implemented by timo++ in response to a similar SO question to yours and then nicely documented by Kaiepi 🤍 in their accepted answer. Please visit and upvote there accordingly. The rest of what I write here is arguably redundant.


    The official doc doesn't mention the solution (passing a :datagram argument to the IO::Socket::Async.Supply method) and using the Datagrams you then get from the supply.

    Here's an example of it using low level taps of supplies at both ends:

    # Server
    
    given IO::Socket::Async .bind-udp('localhost', 3333) {
      .Supply(:datagram)
        .tap: {
          say "Received client data: { .data.gist }";
          IO::Socket::Async.udp.print-to: .hostname, .port, 'Loud and clear!';
        }
    }
    
    # Client
    
    given IO::Socket::Async.udp {
      .print-to: 'localhost', 3333, 'Can you hear me?';
      .Supply
        .tap: {
          say "Received server data: { .gist }";
          IO::Socket::Async.udp.print-to: 'localhost', 3333, 'Great :)';
        }
    }
    
    sleep 1;
    

    displays:

    Received client data: Can you hear me?
    Received server data: Hi!
    Received client data: Great :)