Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re^7: Problem handling 2 simultaneous socket streams

by zentara (Archbishop)
on Oct 04, 2011 at 16:46 UTC ( #929597=note: print w/ replies, xml ) Need Help??


in reply to Re^6: Problem handling 2 simultaneous socket streams
in thread Problem handling 2 simultaneous socket streams

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__

I'm not really a human, but I play one on earth.
Old Perl Programmer Haiku ................... flash japh


Comment on Re^7: Problem handling 2 simultaneous socket streams
Download Code
Re^8: Problem handling 2 simultaneous socket streams
by PhillyR (Acolyte) on Oct 04, 2011 at 18:17 UTC

    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__
      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

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh

        zentara,
        I created a new post for this problem but I think the basic problem now is creating another thread to do additional processing after a thread for monitoring STDIN has been created. Link below:

        http://perlmonks.org/index.pl?node_id=930015

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://929597]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (10)
As of 2014-09-17 18:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (94 votes), past polls