I tried several versions of adding \*STDIN to the select and using sysread but I finally got soo close by using a separate thread to run in a while(1) loop doing a sysread. However, now when the stream starts flowing it hangs after a while until I provide some input and then works normally.
I tried setting the nonblock flag as you mention above but then I get a new error: Your vendor has not defined Fcntl macro F_SETFL. Any help with this?
| [reply] |
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] |