Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^6: Problem handling 2 simultaneous socket streams

by PhillyR (Acolyte)
on Oct 04, 2011 at 16:37 UTC ( #929596=note: print w/ replies, xml ) Need Help??


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

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?


Comment on Re^6: Problem handling 2 simultaneous socket streams
Re^7: Problem handling 2 simultaneous socket streams
by zentara (Archbishop) on Oct 04, 2011 at 16:46 UTC
    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

      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

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (7)
As of 2014-07-31 08:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (246 votes), past polls