http://www.perlmonks.org?node_id=549191


in reply to Re^2: Signal handlers and scoped variables, or Nested subs?
in thread Signal handlers and scoped variables, or Nested subs?

Partially tested. Specifically, I've tested the following:

You should find the following code very flexible. Think of Client as a state machine.

use IO::Select (); use IO::Socket::INET (); use Time::HiRes qw( time ); # Optional. { package Client; use constant ST_CONNECTING => 0; use constant ST_SOMETHING1 => 1; use constant ST_SOMETHING2 => 2; use constant ST_SOMETHING3 => 3; # ... sub new { my ($class) = @_; my $self = bless({ sock => $sock, timeout => time() + 30, wannna_d => 0, # True if we want to disconnect the socket. wannna_w => 1, # True if we want to write to the socket. state => ST_CONNECTING, # ... }); } sub connected { my ($self) = @_; $self->{state } = ST_SOMETHING1; $self->{wanna_w} = 0; # ... } sub disconnected { my ($self) = @_; # ... } sub timed_out { my ($self) = @_; # ... } sub data_available { my ($self) = @_; $self->reset_timeout(); # ... } sub ready_to_write { my ($self) = @_; $self->reset_timeout(); my $state = $self->{state}; if ($state == ST_CONNECTING) { $self->connected(); return; } # ... } sub reset_timeout { my ($self) = @_; $self->{timeout} = $time + 30; } } { my %clients; { my $sock = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => '...', Blocking => 0, # How well does this work in Windows? ); $clients{$sock} = Client->new($sock); } for (;;) { my $time = time; my $min_timeout = 3600; # Just so it isn't undef. my $r_sel = IO::Select->new(); my $w_sel = IO::Select->new(); foreach my $client (values %clients) { my $sock = $client->{sock}; my $wanna_d = $client->{wanna_d}; my $wanna_w = $client->{wanna_w}; my $timeout = $client->{timeout} - $time; if ($wanna_d) { delete($clients{$sock}); next; } if ($timeout <= 0) { delete($clients{$sock}); $client->timed_out(); next; } $min_timeout = $timeout if $min_timeout > $timeout; $r_sel->add($sock); $w_sel->add($sock) if $wanna_w; } # In case a "$client->timed_out();" takes a long time. $timeout -= time() - $time; $timeout = 0.001 if $timeout < 0; last if not %clients; my ($r, $w) = IO::Select->select($r_sel, $w_sel, undef, $timeout); foreach my $sock (@$r) { my $client = $clients{$sock}; next if not $client; # Just in case. if (eof($sock)) { delete($clients{$sock}); $client->disconnected(); } else { $client->data_available(); } } foreach my $sock (@$w) { my $client = $clients{$sock}; next if not $client; $client->ready_to_write(); } } }