Newsgroup: it.comp.lang.perl
Titolo: Socket

Per cortesia chi mi aiuta a capire il funzionamento della lettura di una socket, premetto che non ho esperienza nella gestione di connessione client/server e di protolli.
Cerco brevemente di descrivere il contesto:
devo gestire un demon  server che ha l’esclusivo compito di “ascoltare”, su una specifica porta, l’invio da parte di un client, sempre lo stesso, di request HTTP Post.
Riporto la definizione della socket ed ciclo principale del demon, nel quale una volta acquisita la request cede il controllo ad un thread:
my $socket = IO::Socket::INET->new (
						LocalHost => $ini_hash{'LocalHost'},
						LocalPort => $ini_hash{'LocalPort'},
						Proto => 'tcp',
						Listen => 54000,
						Reuse => 1
						) or die "Impossibile aprire il socket $!\n";
#processo principale 
while (my $con = $socket->accept()) {
	$con->recv($packet,1024);
	print $con "HTTP/1.0 200 OK\r\n\r\n";
	$append->enqueue($packet);
} 
Utilizzando un simulatore per l’invio delle request e monitorando il colloquio fra client e server, con Ethereal, ad ogni request corrisponde l’apertura e chiusura per ogni singola request, dopo il corretto scambio di messaggi, e sin qui tutto bene.
La situazione mi si è complicata quando il client, nell’invio delle request, utilizzando il protocollo HTTP/1.1 connessione permanente che, per quel che sono le mie conoscenze, invia più request sulla stessa socket. Monitorando il colloquio vedo che dopo la prima request il server chiude la socket impedendo l’acquisizione della successiva request.
Innanzi tutto non so se ciò dipende dal mio demon. Ho comunque cercato cercato altre soluzioni, ovvero di leggere il contenuto della socket con un ciclo sotto riportato, e nel quale passo al  thread solo il body della request:
while (my $con = $socket->accept()) {
	while (<$con>) {
		if ($_ =~ /$accessDevice/) {
			print $socket "HTTP/1.1 200 OK\r\n\r\n";
			chop($_);
			$append->enqueue($_);
		}
	}
} 
Utilizzando lo stesso simulatore, in questo modo, lette le righe del header rimane in wait sul body e dopo poco la connessione è chiusa.
Nella speranza di aver descritto in maniera sufficientemente chiara i quesiti che pongo sono:
1 – la modalità di colloquio 8chiusura della socket, non dipende dal mio demon ?
2 – se dipende dal demon come posso gestire correttamente questa situazione.  ?
Ringrazio anticipatamente chiunque sia in grado di darmi qualche indicazione fornendo, se necessario, ulteriori indicazioni.
Buon fine settimana.
Beppe 
-- 
Questo articolo e` stato inviato dal sito web 
http://www.nonsolonews.it

 Beppe 
Spero che questo intervento possa servirti.
Ciao
Roberto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

Roberto C ha scritto:

Innanzi tutto ti ringrazio per la risposta.
La condizione che ho descritto mi è imposta, sul client che invia le request è stato sviluppato un software ad hoc, con il potere di dettare le condizioni, forse, per vincoli legati ai volumi di request inviate, oltre 400 al secondo.
La soluzione che mi proponi l’ho applicata con successo, se ricordi me l’avevi suggerita, a luglio. La differenza con allora è che ad ogni request corrispondeva una connessione, oggi analizzando il traffico con Ethereal vedo che il server chiude la connessione nonostante il client abbia inviato un’altra request.
Ciò che fatico ad immaginare è, dopo la prima recv, come poter capire che la socket contiene una nuova request. Ho trovato un buon testo che descrive il dialogo client server con protocollo HTTP ed è esplicitamente descritto che durante la stessa connessione sono inviate più requets, cambia solo la modalità con cui sono inviate le respons per connessione incanalata o non incanalata.
Con il codice che ho allegato tento, senza successo, di gestire la socket come un file ma acquisisco le righe di header e non il body. Quando provo ad inviare delle request, con il benchmark di Apache, resta in wait e cade per tempo come se non fosse più in ascolto.
Nel frattempo ho modificato la definizione della socket come segue:
my $socket = IO::Socket::INET->new (
						LocalHost => $ini_hash{'LocalHost'},
						LocalPort => $ini_hash{'LocalPort'},
						Proto => 'tcp',
						Listen => 54000,
						Reuse => 1,
						keep_alive => 1,
						SO_REUSEADDR => 1,
						SO_REUSEPORT  => 1
						) or die "Impossibile aprire il socket $!\n";
ma il server continua a chiudere, sembra solo logicamente, le socket. Dando il comando 
netstat -a |grep 8081 |wc -l 
il numero delle socket è di molto inferiore alle prove eseguite in passato.
In merito alla close della socket è, volutamente, omessa. Mi rimane, pertanto il dubbio che la chiusura non sia dipendente dallo script.
Di nuovo grazie per la cortese assistenza.
Buona serata.


      keep_alive => 1,
Questa aggiunta mi fa sospettare che tu ritenga che questo 'keep_alive'
abbia qualcosa a che vedere con il "Connection: keepalive" del protocollo
HTTP/1.1. Magari mi sbaglio.
Comunque, non ho seguito bene il thread, ma mi pare che tu stia cercando di
implementare dei client o server HTTP/1.1 senza evidentemente conoscere le
specifiche del protocollo (e nemmeno tanto le basi della programmazione
basata sui socket).
Non riesco nemmeno a capire perché tu lo stia facendo, visto che esistono
moduli già pronti che implementano il protocollo HTTP/1.1 sia lato server
sia lato client.
Max

Max M. ha scritto:

Le tue considerazioni sono corrette. Cerco, in poche parole di sintetizzare il mio problema:
ho ereditato la situazione, ovvero è stata progettata/realizzata da un altro; la scelta di realizzare il webserver è stata dettata dalla necessità di raccogliere i body di request HTTP Post inviate da un un client, sempre quello, 24 ore su 24, il contenuto dei body sono scritti in un file che, ogni 15 minuti, è chiuso e archiviato. Il volume di request previste, ma già ora superato, è di 400 al secondo. Per completezza a inviare le request dal client è il modulo Cisco AON.
A torto o a ragione le condizioni del colloquio sono imposte, connessione permanente non incanalata con invio di response 200 ok. 
Sto tentando di gestire un’evoluzione, come ho avuto modo di rispondere a Roberto, nella prima fase la connessione era non permanente ed il demon svolgeva egregiamente il suo compito. Ho persino eseguito uno stress test collegando un portatile (client) con cavo cross al server e con l’impiego del benchmarck di Apache ho inviato, per 12 ore, request memorizzando sui 46 file prodotti qualcosa come 47.000.000 di record (circa 1.084 record al secondo).
A conferma di quanto affermi, ho persino il dubbio che ci sia una soluzione applicabile, ho cercato in lungo e in largo ed alla fine ho scritto al blog.
Ti ringrazio, e ringrazio tutti, per l’attenzione e la disponibilità.


 Per completezza a inviare le request dal client è il modulo Cisco AON.
Duqnue, non sono certo di aver capito. Ricapitoliamo.
Il client è un apparato Cisco con l'AON, che invia dati tramite POST HTTP.
Il server lo state facendo voi (o state sistemando qualcosa di già
esistente).
Se è così, chiedo:
 1. sappiamo per certo che il client usa HTTP/1.1 e desidera riutilizzare la
connessione nei modi previsti dal protocollo?
 2. perché dovete scrivere il server in Perl? Non potete invece usare
Apache, usando eventualmente mod_perl per la logica che riguarda la lettura
l'archiviazione delle informazioni?
Max

Max M. ha scritto:

1. Dalle prove eseguite monitorando il traffico con Ethereal, ho anche dei file, direi proprio di si.
2. La scelta he stata dettata dal timore che, la velocità con cui pervengono le request, Apache non fosse in grado di gestire correttamente la raccolta. Questa è la motivazione che mi è stata data a suo tempo (?).
Grazie buon pomeriggio.


 data a suo tempo (?). Grazie buon pomeriggio.
Non ho ragioni di credere che un'implementazione pure-Perl del server abbia
prestazioni migliori di Apache. In ogni caso, non ha senso usare l'intuito
in queste cose, giacché si possono fare misurazioni. Vi consiglio, quindi,
di usare 'ab' o 'ab2' (Apache benchmarking tool) per simulare il numero
desiderato di richieste POST simultanee e valutare il comportamento del
server sotto stress. (Tieni presente che, se usate Apache, il codice che
raccoglie e archivia i dati -se dev'essere in Perl- dovrà girare sotto
mod_perl. Con un traffico di 400 richieste al secondo, l'impiego del CGI è
da escludere.)
Max

Max M. ha scritto:

Grazie.
Buona serata.
