You might want to post a new node, describing your platform. First try this threaded attempt.
#!/usr/bin/perl
use warnings;
use strict;
use Term::ReadKey;
use threads;
$|++;
# I commented out some possible ReadMode settings
#ReadMode('cbreak');
# works non-blocking if read stdin is in a thread
my $thr = threads->new(\&read_in)->detach;
# loop to keep main thread alive
while(1){
print "test\n";
sleep 1;
}
#ReadMode('normal'); # restore normal tty settings
sub read_in{
while(1){
my $char;
if (defined ($char = ReadKey(0)) ) {
print "\t\t$char->", ord($char),"\n";
#process key presses here
if($char eq 'q'){exit}
#if(length $char){exit} # panic button on any key :-)
}
}
}
__END__
| [reply] [d/l] |
Zentara, thank you for your help. I feel like I am so close.
Here's the current behavior
1. Turn on server 2
2. Turn on this proxy (code below)
3. Proxy creates 3 listen sockets (server 1, clients for server 1 and clients for server 2)
4. Have client connection for server 2 stream
5. Proxy displays connection, creates a socket to server 2, server 2 starts sending data to this client. After about 2 seconds of transfer the stream hangs.
6. I try a secondary client for server 2. No connection
7. I press any key on the proxy command prompt and hit enter
8. Server 2 resumes sending data, second client connects and starts to get data
9. Behavior is as would be expected (multiple client connecting, STDIN is being read, no hanging)
How do I get rid needing step 7? Should each of my stream subroutines use the sysread as well? I would like the stream coming from either server to be unmodified
Here is my current code:
#!/usr/bin/perl -w
# -----------------------------
use warnings;
use strict;
use IO::Socket;
use IO::Select;
use Term::ReadKey;
use threads;
use threads::shared;
$|++;
# -----------------------------
# -----------------------------
our @stream1_clients : shared;
our @stream2_clients : shared;
my $stream1_prt = 5555;
my $stream2_prt = 5556;
my $client1_prt = 1100;
my $client2_prt = 1101;
my $ip = '192.168.1.12';
# -----------------------------
# Create Stream 1 listen ------
my $stream1_lsn = new IO::Socket::INET (LocalAddr => $ip,
LocalPort => $stream1_prt,
Type => SOCK_STREAM,
Proto => "tcp",
Reuse => 1,
Listen => 5)
or die "Stream 1 listen socket couldn't be created: $@\n";
# -----------------------------
# Create Client 1 listen ------
my $client1_lsn = new IO::Socket::INET (LocalAddr => $ip,
LocalPort => $client1_prt,
Type => SOCK_STREAM,
Proto => "tcp",
Reuse => 1,
Blocking => 0, #part of issue?
Listen => 5)
or die "Client 1 listen socket couldn't be create: $@\n";
# -----------------------------
# Create Client 2 listen ------
my $client2_lsn = new IO::Socket::INET (LocalAddr => $ip,
LocalPort => $client2_prt,
Type => SOCK_STREAM,
Proto => "tcp",
Reuse => 1,
Blocking => 0, #part of issue?
Listen => 5)
or die "Client 2 listen socket couldn't be create: $@\n";
# -----------------------------
# Add listen sockets to select
my $sockets = new IO::Select();
$sockets->add($stream1_lsn);
$sockets->add($client1_lsn);
$sockets->add($client2_lsn);
# -----------------------------
# Create separate thread for nonblocking read of STDIN
my $thr_in = threads->new(\&read_in)->detach();
#Go into infinite loop, handling connections
while(my @ready = $sockets->can_read) { #got data
foreach my $socket (@ready) { # find which socket sent data
#New Stream1---------------------
if ($socket == $stream1_lsn) {
my $stream1_sock = $stream1_lsn->accept(); #accept stream 1
$stream1_hst = $stream1_sock->peerhost;
print "New stream1 from IP [$stream1_hst]\n";
my $thr_stream1 = threads->new(\&stream1, $stream1_sock)->detach
+();
}
# -----------------------------
#New client1 ------------------
elsif ($socket == $client1_lsn) {
my $client1_sock = $client1_lsn->accept(); #accept client 1
$sockets->add($client1_sock); #add socket to select
my $fileno = fileno $client1_sock;
push (@stream1_clients, $fileno);
$client1_hst = $client1_sock->peerhost;
print "New client for stream 1 @ IP [$client1_hst]\n";
}
# -----------------------------
#New client2 ------------------
elsif ($socket == $client2_lsn) {
my $client2_sock = $client2_lsn->accept(); #accept client 2
$sockets->add($client2_sock); #add socket to select
my $fileno2 = fileno $client2_sock;
push(@stream2_clients, $fileno2);
$client2_hst = $client2_sock->peerhost;
print "New client for stream 2 @ IP [$client2_hst]\n";
#Connection to second server running locally
my $stream2_sock = new IO::Socket::INET(
PeerAddr => 'localhost',
PeerPort => $stream2_prt,
Type => SOCK_STREAM,
Proto => "tcp")
or die "Stream2 socket couldn't be created: $@\n";
my $thr_stream2 = threads->new(\&stream2, $stream2_sock)->detach
+();
}
# -----------------------------
}
}
# Routine called by thread to send stream 1
sub stream1 {
my ($lclient1) = @_;
my $buf1;
if ($lclient1->connected) {
while(defined($buf1=<$lclient1>) {
foreach $fn1 (@stream1_clients) {
open my $fh1, ">&=fn1" or warn $! and die;
binmode($fh1, ":raw");
print $fh1 $buf1;
}
}
}
close ($lclient1);
}
# -----------------------------
# Routine called by thread to send stream 2
sub stream2 {
my ($lclient2) = @_;
my $buf2;
if ($lclient2->connected) {
while(defined($buf2=<$lclient2>) {
foreach $fn2 (@stream2_clients) {
open my $fh2, ">&=fn2" or warn $! and die;
binmode($fh2, ":raw");
print $fh2 $buf2;
}
}
}
close ($lclient2);
}
# -----------------------------
# Read STDIN in nonblocking fashion??
sub read_in {
while (1) {
my $char;
if(defined($char = ReadKey(0)) ) {
if ($char eq 'q') { exit; }
}
}
}
__END__
| [reply] [d/l] |
Should each of my stream subroutines use the sysread as well?
Your code is kind of complex for me to setup and run and test myself.
However, if you are experiencing blocking problems, yes, switch to sysread. The other thing to try is to put a timeout in your select statement, I noticed you have none.
while(my @ready = $sockets->can_read) { #got data
# add a timeout to your select
while(my @ready = $sockets->can_read (.1) ) { } # 100 ms timeout
| [reply] [d/l] |