Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/Stream.pm view on Meta::CPAN
my ( $self, $buffref, $eof ) = @_;
if( length $$buffref >= 16 ) {
my $record = substr( $$buffref, 0, 16, "" );
print "Received a 16-byte record: $record\n";
return 1;
}
if( $eof and length $$buffref ) {
print "EOF: a partial record still exists\n";
}
return 0;
}
The 4-argument form of C<substr()> extracts the 16-byte record from the buffer
and assigns it to the C<$record> variable, if there was enough data in the
buffer to extract it.
A lot of protocols use a fixed-size header, followed by a variable-sized body
of data, whose size is given by one of the fields of the header. The following
C<on_read> method extracts messages in such a protocol.
sub on_read
{
my ( $self, $buffref, $eof ) = @_;
return 0 unless length $$buffref >= 8; # "N n n" consumes 8 bytes
my ( $len, $x, $y ) = unpack "N n n", $$buffref;
return 0 unless length $$buffref >= 8 + $len;
substr( $$buffref, 0, 8, "" );
my $data = substr( $$buffref, 0, $len, "" );
print "A record with values x=$x y=$y\n";
return 1;
}
In this example, the header is C<unpack()>ed first, to extract the body
length, and then the body is extracted. If the buffer does not have enough
data yet for a complete message then C<0> is returned, and the buffer is left
unmodified for next time. Only when there are enough bytes in total does it
use C<substr()> to remove them.
=head2 Dynamic replacement of C<on_read>
Consider the following protocol (inspired by IMAP), which consists of
C<\n>-terminated lines that may have an optional data block attached. The
presence of such a data block, as well as its size, is indicated by the line
prefix.
sub on_read
{
my $self = shift;
my ( $buffref, $eof ) = @_;
if( $$buffref =~ s/^DATA (\d+):(.*)\n// ) {
my $length = $1;
my $line = $2;
return sub {
my $self = shift;
my ( $buffref, $eof ) = @_;
return 0 unless length $$buffref >= $length;
# Take and remove the data from the buffer
my $data = substr( $$buffref, 0, $length, "" );
print "Received a line $line with some data ($data)\n";
return undef; # Restore the original method
}
}
elsif( $$buffref =~ s/^LINE:(.*)\n// ) {
my $line = $1;
print "Received a line $line with no data\n";
return 1;
}
else {
print STDERR "Unrecognised input\n";
# Handle it somehow
}
}
In the case where trailing data is supplied, a new temporary C<on_read>
callback is provided in a closure. This closure captures the C<$length>
variable so it knows how much data to expect. It also captures the C<$line>
variable so it can use it in the event report. When this method has finished
reading the data, it reports the event, then restores the original method by
returning C<undef>.
=head1 SEE ALSO
=over 4
=item *
L<IO::Handle> - Supply object methods for I/O handles
=back
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
( run in 0.788 second using v1.01-cache-2.11-cpan-140bd7fdf52 )