[Chicago-talk] Sockets & Hashes

Steven Lembark lembark at wrkhors.com
Mon Mar 26 09:54:29 PDT 2007


> Can a socket connection be used to send/receive hash information?

# message looks like <size> <space> <frozen content>
# this will send anything you like other than code -- and even
# that if you do it carefully.

use IO::Select;
use Storable qw( nfreeze thaw );

sub send
{
  my ( $socket, $payload ) = @_;

  # without the lenggth the other side has no idea how much
  # data to expect.

  my $message = nfreeze $payload;

  my $buffer  = length $message . ' ' . $message;

  my $select = IO::Select->new( $socket );

  WRITE:
  while( $buffer ne '' )
  {
    $select->can_write( $timeout )
    or die 'Timeout writing';

    # note: error condition => can_write w/ zero bytes written.

    if( my $bytes = eval { syswrite( $socket, $buffer, 1024 ) } )
    {
      substr $buffer, 0, $bytes, '';

      next WRITE;
    }
    elsif
    (
      $! == EWOULDBLOCK ||
      $! == EINTR       ||
      $! == EAGAIN
    )
    {
      warn "Transient write error: $!";
    }
    else
    {
      die 'Failed write';
    }
  }
}

sub recv
{
  my $socket  = shift;

  my $select  = IO::Select->new( $socket );

  my $reply   = '';

  my $message = '';

  my $buffer  = '';

  my $length  = '';

  for(;;)
  {
    # only way out of here is returning the payload or death.
    # caller deals with exceptions.

    $select->can_read( $timeout )
    or die 'Timeout';

    my $buffer  = '';

    if( my $bytes = sysread( $socket, $buffer, $recv_size ) )
    {
      $message .= $buffer;

      # keep reading if the message is not complete, otherwise
      # quite it if the length is known, otherwise attempt to
      # store the length. trailing space in the length won't
      # hurt numeric comparisons.

      $length > length $message
      and next;

      $length
      and return thaw $message

      my $index = index $message, ' ';

      $index > 0
      and $length   = substr $message, 0, $index, '';
    }
    elsif
    (
      $! == EWOULDBLOCK ||
      $! == EINTR       ||
      $! == EAGAIN
    )
    {
      warn "Retrying read: $!";
    }
    else
    {
      # reading zero bytes => EOF on read => closed socket.
      # or something similar: at this point close the socket.

      die "Zero byte read: $!"
    }
  }
}


-- 
Steven Lembark                                         85-09 90th Street
Workhorse Computing                                  Woodhaven, NY 11421
lembark at wrkhors.com                                      +1 888 359 3508


More information about the Chicago-talk mailing list