Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^8: Problem handling 2 simultaneous socket streams

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


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

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__


Comment on Re^8: Problem handling 2 simultaneous socket streams
Download Code
Re^9: Problem handling 2 simultaneous socket streams
by zentara (Archbishop) on Oct 05, 2011 at 09:25 UTC
    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://929629]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (11)
As of 2014-10-30 17:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (208 votes), past polls