class IO::Socket::Async {}

IO::Socket::Async provides asynchronous sockets, for both the server and the client side.

Here is a simple example of a simple "hello world" HTTP server that listens on port 3333:

react {
    whenever IO::Socket::Async.listen('0.0.0.0', 8080) -> $conn {
        await $conn.print: qq:heredoc/END/;
            HTTP/1.1 200 OK
            Content-Type: text/html; charset=UTF-8
            Content-Encoding: UTF-8

            <html>
            <body>
                <h1>Incoming request:</h1>
            <pre>
            END
        whenever $conn.Supply.lines -> $line {
            $conn.say: $line;
            if $line ~~ "" {
                await $conn.print: "</pre></body></html>";
                $conn.close;
            }
            LAST { say "closed connection"; }
        }
    }
    CATCH {
        default {
            say .^name, ': ', .Str;
            say "handled in $?LINE";
        }
    }
}

And a client that connects to it, and prints out what the server answers:

await IO::Socket::Async.connect('127.0.0.1', 3333).then( -> $promise {
    given $promise.result {
        .print("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n");
        react {
            whenever .Supply() -> $v {
                $v.print;
                done;
            }
        }
        .close;
    }
});

IO::Socket::Async can also send and receive UDP messages An example server that outputs all the data it receives would be:

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

react {
    whenever $socket.Supply -> $v {
        if $v.chars > 0 {
            say $v;
        }
    }
}

And an associated client might be:

my $socket = IO::Socket::Async.udp();
await $socket.print-to('localhost', 3333, "Hello, Raku!");

The CATCH phaser can be included to deal specifically with problems that might occur in this kind of sockets, such as a port being already taken:

react {
    whenever IO::Socket::Async.listen('0.0.0.0', 3000) -> $conn {
        whenever $conn.Supply.lines -> $line {
            $conn.print: qq:heredoc/END/;
                HTTP/1.1 200 OK
                Content-Type: text/html; charset=UTF-8
                Content-Encoding: UTF-8

                <html>
                <body>
                    <h1>Hello World!</h1>
                    <p>{ $line }</p>
                </body>
                </html>
                END
            $conn.close;
        }
        QUIT {
            default {
                say .^name, '', .Str;
                say "handled in line $?LINE";
            }
        }
    }

}
# Will print this, if address 3000 is already in use:
# X::AdHoc→ address already in use
# handled in 23

Main difference with using other phasers such as CATCH is that this kind of exception will be caught within the whenever block and will put exiting the program, or not, under your control.

Methods§

The IO::Socket::Async cannot be constructed directly, either connect or listen (for TCP connections) or udp or bind-udp (for UDP data) should be used to create a client or a server respectively.

method connect§

method connect(Str $host, Int $port --> Promise)

Attempts to connect to the TCP server specified by $host and $port, returning a Promise that will either be kept with a connected IO::Socket::Async or broken if the connection cannot be made.

method connect-path§

method connect-path(Str $path --> Promise)

Attempts to connect to a unix domain stream socket specified by $path, returning a Promise that will either be kept with a connected IO::Socket::Async or broken if the connection cannot be made.

method listen§

method listen(Str $host, Int $port --> Supply)

Creates a listening socket on the specified $host and $port, returning a Supply to which the accepted client IO::Socket::Asyncs will be emitted. This Supply should be tapped start listening for client connections. You can set $port to 0 if you want the operating system to find one for you.

The IO::Socket::Async::ListenSocket returned by calling the tap method on the supply returned represents the underlying listening TCP socket, which can be closed using its close method. If $port was set to 0, you can get the port the socket ended up with using its socket-port method.

method listen-path§

method listen-path(Str $path)

Creates a unix domain stream listening socket on the specified $path, returning a Supply to which the accepted client IO::Socket::Asyncs will be emitted. This Supply should be tapped start listening for client connections.

The IO::Socket::Async::ListenSocket returned by calling the tap method on the supply returned represents the underlying listening TCP socket, which can be closed using its close method.

method udp§

method udp(IO::Socket::Async:U: :$broadcast --> IO::Socket::Async)

Returns an initialized IO::Socket::Async client object that is configured to send UDP messages using print-to or write-to. The :broadcast adverb will set the SO_BROADCAST option which will allow the socket to send packets to a broadcast address.

method bind-udp§

method bind-udp(IO::Socket::Async:U: Str() $host, Int() $port, :$broadcast --> IO::Socket::Async)

This returns an initialized IO::Socket::Async server object that is configured to receive UDP messages sent to the specified $host and $port and is equivalent to listen for a TCP socket. The :broadcast adverb can be specified to allow the receipt of messages sent to the broadcast address.

method print§

method print(IO::Socket::Async:D: Str $str --> Promise)

Attempt to send $str on the IO::Socket::Async that will have been obtained indirectly via connect or listen, returning a Promise that will be kept with the number of bytes sent or broken if there was an error sending.

method print-to§

method print-to(IO::Socket::Async:D: Str() $host, Int() $port, Str() $str --> Promise)

This is the equivalent of print for UDP sockets that have been created with the udp method, it will try send a UDP message of $str to the specified $host and $port returning a Promise that will be kept when the data is successfully sent or broken if it was unable to send the data. In order to send to a broadcast address the :broadcast flag must have been specified when the socket was created.

method write§

method write(IO::Socket::Async:D: Blob $b --> Promise)

This method will attempt to send the bytes in $b on the IO::Socket::Async that will have been obtained indirectly via connect or listen, returning a Promise that will be kept with the number of bytes sent or broken if there was an error sending.

method write-to§

method write-to(IO::Socket::Async:D: Str() $host, Int() $port, Blob $b --> Promise)

This is the equivalent of write for UDP sockets that have been created with the udp method. It will try send a UDP message comprised of the bytes in the Blob $b to the specified $host and $port returning a Promise that will be kept when the data is successfully sent or broken if it was unable to send the data. In order to send to a broadcast address the :broadcast flag must have been specified when the socket was created.

method Supply§

method Supply(:$bin, :$buf = buf8.new --> Supply)

Returns a Supply which can be tapped to obtain the data read from the connected IO::Socket::Async as it arrives. By default the data will be emitted as characters, but if the :bin adverb is provided a Buf of bytes will be emitted instead, optionally in this case you can provide your own Buf with the :buf named parameter.

A UDP socket in character mode will treat each packet as a complete message and decode it. In the event of a decoding error, the Supply will quit.

On the other hand, a TCP socket treats the incoming packets as part of a stream, and feeds the incoming bytes into a streaming decoder. It then emits whatever characters the decoder considers ready. Since strings work at grapheme level in Raku, this means that only known complete graphemes will be emitted. For example, if the UTF-8 encoding were being used and the last byte in the packet decoded to a, this would not be emitted since the next packet may include a combining character that should form a single grapheme together with the a. Control characters (such as \n) always serve as grapheme boundaries, so any text-based protocols that use newlines or null bytes as terminators will not need special consideration. A TCP socket will also quit upon a decoding error.

method close§

method close(IO::Socket::Async:D: )

Close the connected client IO::Socket::Async which will have been obtained from the listen Supply or the connect Promise.

In order to close the underlying listening socket created by listen you can close the IO::Socket::Async::ListenSocket. See listen for examples.

method socket-host§

method socket-host(--> Str)

Returns the IP address of the local end of this socket.

method peer-host§

method peer-host(--> Str)

Returns the IP address of the remote end of this socket.

method socket-port§

method socket-port(--> Int)

Returns the port of the local end of this socket.

method peer-port§

method peer-port(--> Int)

Returns the port of the remote end of this socket.

method native-descriptor§

method native-descriptor(--> Int)

Returns the file descriptor of this socket.