class IO::Socket::Async
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.