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::Async
s 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::Async
s 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.