Asynchronous socket in TCP or UDP
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
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( ->);
IO::Socket::Async can also send and receive UDP messages An example server that outputs all the data it receives would be:
my = IO::Socket::Async.bind-udp('localhost', 3333);react
And an associated client might be:
my = IO::Socket::Async.udp();await .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# 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.
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(Str , Int --> 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 listen(Str , Int --> 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 udp(IO::Socket::Async: : --> 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(IO::Socket::Async: Str() , Int() , : --> 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(IO::Socket::Async: 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(IO::Socket::Async: Str() , Int() , 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(IO::Socket::Async: Blob --> 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(IO::Socket::Async: Str() , Int() , Blob --> 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(:, : = 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(IO::Socket::Async: )
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(--> Str)
Returns the IP address of the local end of this socket.
method peer-host(--> Str)
Returns the IP address of the remote end of this socket.
method socket-port(--> Int)
Returns the port of the local end of this socket.
method peer-port(--> Int)
Returns the port of the remote end of this socket.
method native-descriptor(--> Int)
Returns the file descriptor of this socket.