1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
use IO::Handle; use IO::Select; use constant { BLOCKSIZE => 8192 }; my $c0 = ...; # Connection to client 0 my $c1 = ...; # Connection to client 1 # Make connections non-blocking $c0->blocking(0); $c1->blocking(0); # Initialize receiving selector and buffer table my $rcvsel = IO::Select->new($c0, $c1); my %rcvbuf = ($c0 => '', $c1 => ''); # Setup target mapping my %sndtgt = ($c0 => $c1, $c1 => $c0); # Initialize sending selector and buffer table my $sndsel = IO::Select->new(); my %sndbuf = ($c0 => $rcvbuf{$c1}, $c1 => $rcvbuf{$c0}); # Loop while data has to be received or sent while ($rcvsel->count > 0 or $sndsel->count > 0) { my @ready = $rcvsel->can_read(); for (@ready) { # If there is incoming data, determine receiving buffer and fill it my $buf = \$rcvbuf{$_}; my $len = $_->sysread($$buf, BLOCKSIZE, length($$buf)); if (defined $len) { if ($len > 0) { # If data was received, add the output target to the sending selector $sndsel->add($sndtgt{$_}); } else { # At end of stream, remove the input from the receiving selector $rcvsel->remove($_); } } else { die "read error: $!"; } } @ready = $sndsel->can_write(); for (@ready) { # If the connection is ready for output, try to flush the buffer my $buf = \$sndbuf{$_}; my $len = $_->syswrite($$buf); if (defined $len) { # If data was sent, remove it from the buffer substr($$buf, 0, $len) = ''; if (length($$buf) <= 0) { # If the buffer is empty, remove the output target from the sending selector $sndsel->remove($_); } } else { die "write error: $!"; } } } # All data has been transferred, so we close the streams $c0->close(); $c1->close();