Newsgroup: it.comp.lang.perl
Titolo: Server che "risponde" a piu' client

Ciao,
come faccio a far ascoltare ad un'applicazione server piu' client?
Cioe' se io faccio una cosa di questo tipo:
use IO::Socket;
$server = IO::Socket::INET->new
(
	LocalPort => 4000,
	Type      => SOCK_STREAM,
	Reuse     => 3,
	Listen    => SOMAXCONN
) or die "Could not open";
while ($client = $server->accept()) {
print $client 'Hello';
print <$client>;
}
close($server);
Il mio server ascolta solo il primo che si collega.
Ho una discreta dimestichezza col Perl ma fino ad ora non avevo mai
provato la programmazione con i socket...
A proposito: avete qualche link carino in merito?
Grazie,
Dark Wave

 come faccio a far ascoltare ad un'applicazione server piu' client?
devi fare un forking-server o un preforking-server (e.g. Apache) ecc
info su:
http://safari.oreilly.com/main.asp?bookname=cookbook&snode=335
e nodi attigui

Grazie


Che ne dite di questa soluzione?
Non usa fork e semplicemente fa un loop sul server, verifica se ci
sono nuovi socket da aprire, chiude quelli morti e ascolta quelli che
sono collegati.
Il tutto creando un numero crescente di handle.
#!perl
use Socket;
# Funzione per leggere una riga di input... tipo <HANDLE>
sub readline {
	my $filehandle = $_[0];
	my $c='';
	my $retstr='';
	my $endoffile=0;
	while ($c ne "\n" && ! $endoffile) {
		if (sysread($filehandle, $c, 1) > 0) {
			$retstr = $retstr . $c;
		}
		else {
			$endoffile=1;
		}
	}
 
	return $retstr;
}
#Leggo la porta sulla quale lavorerà il server
($port) = @ARGV;
#Valore di default della porta
$port ||= 4000;
#Dati presi sul canale tcp
($name, $aliases, $protocol) = getprotobyname('tcp');
#Scrivo sullo schermo la porta che useremo
print "Port in uso: $port...\n";
#Creo il socket
socket(S,AF_INET,SOCK_STREAM,$protocol) or die "socket : $!";
#Creo il collegamento con bind. pack serve per preparare la variabile
$this da usare con bind
$sockaddr = 'S n a4 x8';
#pack TEMPLATE
#Takes a LIST of values and converts it into a string using the rules
given by the TEMPLATE. The resulting string is the concatenation of
the converted values. Typically, each converted value looks like its
machine-level representation. For example, on 32-bit machines a
converted integer may be represented by a sequence of 4 bytes.
$this = pack($sockaddr, AF_INET, $port, "\0\0\0\0");
#bind SOCKET,NAME
#Binds a network address to a socket, just as the bind system call
does. Returns true if it succeeded, false otherwise. NAME should be a
packed address of the appropriate type for the socket.
bind(S, $this) || die "bind : $!";
#listen SOCKET,QUEUESIZE
#Does the same thing that the listen system call does. Returns true if
it succeeded, false otherwise.
listen(S, 10) || die "listen: $!";
#Seleziona lo Standard Output
select(S);
#Auto Flush!?
$| = 1;
select(STDOUT);
$con = 0;
######################################### CICLO INFINITO DI ASCOLTO DA
PARTE DEL SERVER #####
@frasi = ();
while (1) {
	$rin = $win = $ein = '';         
	vec($rin, fileno(S), 1) = 1;
 
	foreach (@sockets) {
		if ($_ ne "") {
			vec($rin, fileno($_), 1) = 1;
		}
	}	
	print "In ascolto...\n";
	($numready, $timeleft) =  select($rout=$rin, undef, undef,
undef);
	print "Qualcuno si collega...\n";
 
	#Questo if verifica che arriva qualcosa su S cioe' sul socket
del server
	if (vec($rout, fileno(S), 1)) {
		print "Nuova connessione.\n";
		#Creiamo un nuovo socket nell'array (usiamo il
contatore $con)
		$con++;
		$sockets[$con - 1] = "NUOVOSOCKET".$con;
		#Selezioniamo momentaneamente il nuovo socket per la
connesione
		($addr = accept($sockets[$con - 1], S)) || die $!;
		select($sockets[$con - 1]);
		$|=1;
		select(STDOUT);
		($af,$port, $inetaddr) = unpack($sockaddr, $addr);
		@inetaddr = unpack('C4', $inetaddr);
		# tell the other clients who just connected
		foreach (@sockets) {
				if ($_ ne "") {
				print $_ 
				"Connessione con indirizzo remoto
@inetaddr\n";
				}
		}		
	}
	else { #Un client al quale è stato assegnato il socket cerca
di comunicare col server
		$sockcount = 0;
		foreach (@sockets) {
			$sockcount++;
			$thesocket = $_;
			if (vec($rout, fileno($thesocket), 1)){
				#Chiuderemo la connessione se il
client non risponde
				$data = &readline($thesocket);
				if (! length($data)) {
					#Se la lunghezza di $data è 0
il client è chiuso
					print "Client numero
$thesocket scollegato!\n";
					close($thesocket);
					$sockets[$sockcount-1] = "";
					foreach (@frasi) {
						print $_;
					}
 
				}
				else {
					print "Il client su $sockcount
scrive: $data\n";
					print $thesocket "Hai detto
$data?\n";
					push @frasi, $data;
				}
			}
		}
	}
}
Pensate sia troppo dispendioso in termini di risorse?
Oppure e' semplicemente una soluzione troppo lenta?
E' un bene non usare fork?
Fatemi sapere,
Dark Wave