Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I have the following piece of code. Works great for one person, and then as soon as that person is finished it works great for the next. How can i get it to broadcast everything coming from one port to the other port all the time.
use IO::Select; use IO::Socket; my $client_port; my $rtk_connection; my $listening_port; my $rtk_port; my $rtk_ip; my $accepted_client; $listening_port=8019; $rtk_port=4004; $rtk_ip='000.000.000.000'; $client_port=IO::Socket::INET->new('LocalPort'=>$listening_port, 'Reus +e'=>1, 'Listen'=>512, 'Proto'=>'tcp') || warn "Can not create to list +ening socket on port $listening_port: $!\n"; $rtk_connection= IO::Socket::INET->new('PeerAddr'=>$rtk_ip, 'PeerPort' + =>$rtk_port, 'Reuse'=>1, 'Proto'=>'tcp') || warn "Can not create rtk + socket on IP $rtk_ip and port $rtk_port: $!\n"; $SIG{'CHLD'}='IGNORE'; while(1){ $accepted_client=$client_port->accept() ; if($accepted_client){ print "Client accepted\n"; } if(!$accepted_client){ print "Client could not be accepted: $!\n"; next; } $spawn=fork(); if(!defined($spawn)){ print "Could not spawn child process: $!\n"; } elsif($spawn == 0){ $client_port->close(); print "Spawned child A\n"; &rtk($accepted_client, $rtk_connection); } else{ print "Spawned child B\n"; $accepted_client->close(); } } sub rtk{ ($ac,$rs)=@_; $ac->autoflush(0); $rs->autoflush(0); while($ac){ $drl=sysread($rs, $rd, 1024); if(!$drl){ print "No stream: $!\n"; exit(0); } $dwl=syswrite($ac, $rd, 1024); if(!$dwl){ print "Client Disconnected: $!\n"; exit(0); } } }
thanks,

20040603 Edit by jeffa: Changed title from 'Sockets'

Replies are listed 'Best First'.
Re: Single user to multi user socket server
by Thelonius (Priest) on Jun 01, 2004 at 23:15 UTC
    Possibility 1: open 1 rtk_connection per accepted connection. That is, do the follow in the child after the fork:
    $rtk_connection= IO::Socket::INET->new('PeerAddr'=>$rtk_ip, 'PeerPort' + =>$rtk_port, 'Reuse'=>1, 'Proto'=>'tcp') || warn "Can not create rtk + socket on IP $rtk_ip and port $rtk_port: $!\n";
    Of course, whether you can do that depends on what application you're connecting to on port 4004.

    Possibility 2: Instead of forking, use select to be able to read from any open socket. See IO::Select for a sketchy example.

      You are correct in your first thought. I have an application using the the reverse method working fine. But I am connection to a source that allows only one connection. I tried the IO::Select idea. but it seems to block on every client but the one.. am I just missing something or just totally lost. I am trying to get this to work on a Win2K platform. any help would be great. Just enough so i can get my information to all the clients at the same time. I am slowly running out of hair on this.. and so is everyone else
Re: Single user to multi user socket server
by tachyon (Chancellor) on Jun 02, 2004 at 02:00 UTC

    What you need to do appears a little sketchy. If the issue is that you need lots of clients to talk to a server that will only accept a single connection then the answer is you need a proxy.

    Client --> P Client --> R Client --> O ------> Single Conn Server Client --> X Client --> Y

    Here is some simple code for a server that will handle multiple connections from clients.

      Unfortunately you mix stdio with select here, which makes it rather easy to hang this code. If a client ever sends an incomplete line and then waits, the server will get a readability select for the socket to that client, and then the <$fh> will hang until the client bothers to send a newline (easily demonstrated by setting the telnets you test with to character mode)

      The write back is also potentially blocking, so can also hang.

      There is also the issue of clients that don't send a proper "exit" but just close the connection (maybe a ^C or a crash). The write back you do for them will cause a SIGPIPE and the program will exit.

      I think that the easiest way to write this kind of proxy without all these blocking issues is by using POE. That already takes care of all these issues.

        All valid point. I have updated the code to avoid STDIO and added some error handling. For my own learning I would be interested what you would now change. The main issue now is that if a client hangs writing to the proxy it will block. What is the best approach to this sort of issue? Can you point me towards the best docs?

        cheers

        tachyon