Re: simple multithread daemon

[email protected] (Dean Arnold) Wed, 14 Nov 2007 08:23:40 -0800
Newsgroups perl.ithreads
Message-ID <[email protected]>
See embedded updates below:

jack ciabatta wrote:
> Mmhh... I'm trying with threads->exit();.. any suggests? Could be
> useful a similar "simple, practical and complete" example on cpan? For
> newbies. It would be great.
> 
> Regards,
> Jack
> 
> 
> my $port    = 2500;
> my $timeout = 60;
> 
> $| =1;
> 
> my $server = IO::Socket::INET->new (
> 	Proto     => 'tcp',
> 	LocalPort => $port,
> 	Listen    => SOMAXCONN,
> 	Timeout   => $timeout,
> 	ReuseAddr => 1
> ) or die "Error: can't create listening socket : $!\n";
> 
> while (my $client = $server->accept()) {
> 	my $thr = threads->create("listen_to_client", $client);
> 	my $thr1 = threads->create("stdin_to_client", $client);
> 	print "Client connected ", $thr->tid,"\n";
> 	$thr->detach;
> 	$thr1->detach;

#
#	is this trip really necessary ?
#
# 	$thr->detach;
# 	$thr1->detach;

> }
> 
> exit(0);
> 
> sub listen_to_client {
> 	my ($client) = @_;
> 	my $tid = threads->tid();
> 	while (my $get = <$client>) {
> 		print "client ($tid) : $get";
> 		print $client $get;
> 	};
> 	print "Client closed\n";
> 	close $client;

#
#	better to exit a thread with a value
#
	return 1;

> }
> 
> sub stdin_to_client {
> 	my ($client) = @_;
> 	while (my $msg = <STDIN>) {
> 		print $client $msg;
> 		if ($msg =~ /exit/i){
> 			print "exit\n";
> 			close $client if $client;

#
#	replace the following:
#

> 			#threads->exit() if threads->can('exit');
> 			threads->exit();

#
#	with
#
			last;

> 		}
> 	}
> 	print "stdin thread ended\n";

	return 1;

> }
> 

With all that said, I think you'll find the updated solution
less than satisfactory. Unfortunately, thread startup in Perl
takes a very long time, so spawning a thread for each new socket
connection is probably a bad idea.

So I'd suggest a couple of threads upfront, and an assoc. message queue
to dispatch sockets, e.g., (note: this is not complete, and I'm not
too certain what your app is trying to accomplish, as there are some
issue esp. wrt using the same STDIN for possibly many clients):

use threads;
use Thread::Queue;

my $fromq = Thread::Queue->new();
my $toq = Thread::Queue->new();
my $doneq = Thread::Queue->new();
my $reader = threads->create(\&listen_to_client);
my $writer = threads->create(\&stdin_to_client);

my $port    = 2500;
my $timeout = 60;
$| =1;

my $server = IO::Socket::INET->new (
	Proto     => 'tcp',
	LocalPort => $port,
	Listen    => SOMAXCONN,
	Timeout   => $timeout,
	ReuseAddr => 1
) or die "Error: can't create listening socket : $!\n";

while (my $client = $server->accept()) {
	$fromq->enqueue(fileno($client));
	$toq->enqueue(fileno($client));
	print "Client connected \n";
	$done = $doneq->dequeue;
	# probably more stuff here to untangle this mess
}

sub listen_to_client {
	my $tid = threads->tid();
	while (1) {
		my $fd = $fromq->dequeue;
		last if $fd eq 'STOP';
		open my $client, '+>>&=', $fd;
		while (my $get = <$client>) {
			print "client ($tid) : $get";
			print $client $get;
		};
		print "Client closed\n";
		close $client;
		$doneq->enqueue('CLIENT DONE');
	}
	return 1;
}

sub stdin_to_client {
	while (1) {
		my $fd = $toq->dequeue;
		last if $fd eq 'STOP';
		open my $client, '+>>&=', $fd;
		while (my $msg = <STDIN>) {
			print $client $msg;
			if ($msg =~ /exit/i) {
				print "exit\n";
				close $client;
				$doneq->enqueue('STDIN DONE');
				last;
  			}
		}
		print "stdin thread ended\n";
	}
	return 1;
}

HTH,
Dean Arnold
Presicient Corp.