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

Fellow Monks,

I am currently creating a server / multi-client program.

The tool is supposed to query each client about changes in a set of (locally) defined files. The clients are to send the filenames back to the server.

The server should accept the client connection and move the handling to a seperate thread to wait for a new connection. When the user clicks a button, the server will send a command to the client, triggering the local process.

Until now I have only worked withone client, which I block by having it waiting for a queue to conatain something. It would work the same with mulitple clients, but: As I can't be sure how many conenctions I will get, I can't create the queues at program start. ... Well I could create a set of queues larger the my max amount of expected connections, but having dummy queues around isn't very elegant, I believe.

So I have thought about creating the queues after connection of a client and giving it a name like: $restque1 , $restque2, .. I tried doing so with ${restque."$i"}... where $i is the no of connection. But that doesn't work. It gives me an error: Can't declare scalar dereference in "our" at ISIS-OTN.pl line 905, near "} ="

Any help on how to set the threads to sleep and wake them on a button click?

My code looks like this:
sub PortListener { ########################### # Listening and monitoring Client connections # ########################### my $Thread; my $client_name; my $lsn = new IO::Socket::INET(Listen => 1, LocalPort => $port); my $sel = new IO::Select($lsn); my $j; while(my @ready = $sel->can_read) { # as long a +s we can read from foreach my $fh (@ready) { if($fh == $lsn) { # Create a new socket my ($new, $c_addr) = $lsn->accept; $sel->add($new); my ($client_port, $client_ip) = sockaddr_in($c_addr); my $client_ipnum = inet_ntoa($client_ip); my $i; for $i ( 0 .. $#HostList ) { if ($client_ipnum eq $HostList[$i][1]){ $client_name = $HostList[$i][0]; $HostList[$i][2] = 1; my $dummy_name = "HostConn_$i"; $main->$dummy_name->Text("connected"); $main->$dummy_name->Change( -foreground => [ 0 +, 255, 0 ] ); $main->$dummy_name->InvalidateRect(1); $j = $i; last; } } print "got a connection from: $client_name [$client_ip +num]\n"; if ($client_name eq "Win1") { my $Thread = threads->create( "nautserver", $new); + #start the echo-server as a seperate thread } else { my $Thread = threads->create( "restoreserver", $ne +w, $j); #start the echo-server as a seperate thread our ${restque."$j"} = Thread::Queue->new; } #$Thread->detach(); } else { $sel->remove($fh); my $client_ip = IO::Socket::INET::peeraddr($fh); my $client_ipnum = inet_ntoa($client_ip); print "$client_ipnum resigned \n"; STDOUT->autoflush(1); my $i; for $i ( 0 .. $#HostList ) { if ($client_ipnum eq $HostList[$i][1]){ $client_name = $HostList[$i][0]; $HostList[$i][2] = 0; my $dummy_name = "HostConn_$i"; $main->$dummy_name->Text("disconnected"); $main->$dummy_name->Change( -foreground => [ 2 +55, 0, 0 ] ); $main->$dummy_name->InvalidateRect(1); last; } } if ($client_name eq "Win1") { $main->NautActualDisp->Text("connecting ..."); $run->RunNautActualDisp->Text("connecting ..."); } $fh->close; $go->enqueue("2"); # This tells our nautserver that + it should terminate, as we will reopen a new socket } } } } sub restoreserver{ my $session = $_[0]; my $hostno = $_[1]; print "Server for host number $hostno started\n"; STDOUT->autoflush(1); while(1) { # keep looping for ever print "waiting for button\n"; my $queuedvar = ${restque."$hostno"}->dequeue; # sleep unti +l something is in the queue print "Button clicked"; # or do something useful later } }
and a snippet from the other connection manager:
while(1) { # keep looping for ever my $queuedvar = $go->dequeue; # sleep until something is in + the queue if ($queuedvar eq "2") { # if it's a 2 terminate last; } # else go on if ($use_startstop == 1) { $startstoppdu = "True"; } elsif ($use_startstop == 0) { $startstoppdu = "False"; } $send_data = "PUT:" . $nautilus_auto . ":" . $startstoppdu +; $session->send($send_data); $session->recv($received_data,10000); my @data = split(/:/,$received_data); $nautilus_win=$data[1]; $startstoppdu = $data[2]; if ($startstoppdu eq "True") { $use_startstop = 1; } elsif ($startstoppdu eq "False") { $use_startstop = 0; } }
Thanks a billion for your help.
Sven

Replies are listed 'Best First'.
Re: Creating queues for multiple threads on connection of TCP client
by BrowserUk (Patriarch) on Sep 02, 2009 at 09:00 UTC

    Presumably you were trying to use a symbolic global so that your thread could gain access to the queue handle by doing the same?

    That isn't going to work. Besides that you have the syntax for the symbolic variable instantiation worng, each thread gets its own copy of globals anyway, so tehy would be different entities with the same name.

    But you don't need to do that anyway. Just create the Q before you start the threads, and instead of passing the queue number (your $j) to the thread, pass the queue handle itself:

    my $Q = Thread::Queue->new; my $Thread = threads->create( "restoreserver", $new, $Q);

    If you also need access to the queues from the code that calls PortListener(), (and don't want to return the queue handle from the sub), then also assign the handle to a global array:

    our @queues; push @queues, Thread::Queue->new; my $Thread = threads->create( "restoreserver", $new, $queues[ -1 ] + );

    Now everone has access without needing to use symbolic variables.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.