I tried to program a ONE-to-MANY Socker-Server solution based on Patric Haller's (www.haller.ws) threadedChatServer.pl. I add (see below) the server and a client which dies after 5 received lines.
My problem with this code is that so many lines are lost until the second line finally arrives at the listener.
If you run both, just look at the counter i: (var $i). I assume that $send is re-assigned many, many times before it was send, but why is the first line correctly send (and not re-written)?
Pls remark that a recent received line is glued to $got ($go .= $_;) so that several line are printed at once (without the counter i:)
Is there no other solution than creating a hash with the lines for each client? like:
instead of a simpleforeach $client (keys %h) { lock($h{$client}) $h{$client} .= randLine(); cond_broadcast($h{$client}); }
OK, here is the Radio-Sender (Socket-Server):lock($send) $send = randLine(); cond_broadcast($send);
And this is the Radio-Listener (Socket-Client):#!/usr/bin/perl =pod# This is a ONE-to-MANY Socket-Server, that sends to all Socket-Clients the same information (lines).# The Clients can connect and disconnect whenever they like to (on the f +ly) and they will get what is actually send by this server based on Patrick Haller's threadedChatServer.pl http://www.haller.ws =cut $|++; use 5.008; # 5.8 is required for stable threading use strict; use warnings; use threads; # pull in threading routines use threads::shared; # and variable sharing routines # Lines to send and to get our $send : shared = ''; # lines to send our $got : shared = ''; # lines got and meant for Big-Mama our $NoC : shared = 0; # No. of Clients currently connected $SIG{PIPE} = 'ignore'; sub ignore { ; } #We ignore SIGPIPEs generated by clients trying to work #with closed connections. SIGPIPEs, if not handled, cause deat +h. my $rT = threads->new(\&RadioTower::run); my $i = 0; my $break =0; while (1) { # Big-Mama-loop if ( !$NoC ) # do nothing if nobody is listening { if ($got) { # for safty reasons lock($got); print "i:$i\t", $got; print "\tBREAK\n"; $got = ''; cond_broadcast($got); $i=0; } print ( (++$i%10) ? '.' : "\n." ); $break = 0; sleep 2; next; } if (!$break) { $break++; $i=0; print "\n" } # sender lock($send); $send = ++$i.': '.randLines(); cond_broadcast($send); # listener requests if ($got) { lock($got); print "i:$i\t", $got; $got = ''; cond_broadcast($got); } } sub randLines { my @randomLines = ( 'Sample Line 0', 'Sample Line 1', 'Sample Line 2', 'Sample Line 3', 'Sample Line 4', 'Sample Line 5', 'Sample Line 6', ); return $randomLines[int(rand(7))]."\r\n"; } ##### package Reader; use threads; use threads::shared; sub new { # lock($got); # $got .= "Reader: @_\n"; # cond_broadcast($got); my $pkg = shift; my $self = { @_ }; return bless($self, $pkg); } sub run { my $self = Reader->new(@_); my $socket = $self->{client}; while(<$socket>){ #get input from chat client lock($got); #then raise our hand until the teacher + calls $got .= $self->{id}.': '.$_; cond_broadcast($got); #then tell the class what chatclient s +aid } #Locks are dynamically scoped, so we just gave up lock on +$send } #When we fall off our $socket loop, we return, ending our +thread. ##### package Writer; use threads; use threads::shared; sub new { # lock($got); # $got .= "Writer: @_\n"; # cond_broadcast($got); my $pkg = shift; my $self = { @_ }; return bless($self, $pkg); } sub run { my $self = Writer->new(@_); my $socket = $self->{client}; print $socket 'iniLine:',$send; while(1){ lock($send); #wait till teacher calls on us cond_wait($send); #then release lock and wait until someone + speaks print $socket $send or last; # if client went away, kill this thread by just return'ing } lock($got); $got .= $self->{id}.": bye\r\n"; cond_broadcast($got); lock($NoC); $NoC--; cond_broadcast($NoC); } ############### # package RadioTower; #: this is the Socket-Server - Listener use threads; use threads::shared; use IO::Socket::INET; # and rock the sock et sub run { my $self = {}; bless $self; my $server = IO::Socket::INET->new(LocalPort => 1234, Type => SOCK +_STREAM, Reuse => 1, Listen => 10) or die $!; while (my $client = $server->accept()){ #forea +ch $client scalar($client) =~ /GLOB\((.+?)\)/; # the GLOB is taken as id +- why not my $id = $1; lock($got); $got .= "newClient, ID:$id\n"; cond_broadcast($got); my $r = threads->new(\&Reader::run, client => $client, id => $ +id); # spawn a Reader and $r->detach(); # l +et them run along my $w = threads->new(\&Writer::run, client => $client, id => $ +id); # spawn a Writer and $w->detach(); lock($NoC); $NoC++; cond_broadcast($NoC); } } #When we fall off our $socket loop, we return, ending our thr +ead.
#!/usr/bin/perl #listener is dieing after 5 lines # it send a line back as soon it has got one my $SOCKET =call(); $|++; my $i = 0; while (defined(my $line = <$SOCKET>)) { print $line; die if (++$i >= 5); print $SOCKET "Hallo from Austria from pid: $$\r\n"; } sub call { #: connect to socket use Socket; my ($remote,$port, $iaddr, $paddr, $proto, $line); $remote = shift || 'localhost'; #: ip-Adr of the pc; default +localhost $port = shift || 1234; #: port to use for connetion +default port: 2222 if ($port=~ /\D/) { $port = getservbyname($port, 'tcp') } die "No port" unless $port; $iaddr = inet_aton($remote) || die "no host: $ +remote"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); socket (SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $ +!"; # connect(SOCK, $paddr) || die "$remote,$port,$proto => conn +ect: $!"; connect(SOCK, $paddr) || return 0; #"$remote,$port,$proto = +> connect: $!"; print "calling $remote \@ $port\n"; select((select(SOCK),$|++)[0]); return \*SOCK; ##: Ref. to handel to the socket }
Edit by tye, add READMORE
In reply to ONE-to-MANY Socket-Server by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |