Newsgroup: it.comp.lang.perl
Titolo: socket udp

Salve,
     ho un problema con i socket, non riesco a far ricevere un piccolo 
server udp:
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
socket(_RSOCK, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or return "";
my $ipaddr   = inet_aton("127.0.0.1");
my $portaddr = sockaddr_in(0, $ipaddr);
bind(_RSOCK, $portaddr);
my ( $nport, $naddr );
($nport, $naddr) = sockaddr_in(getsockname(_RSOCK));
my $buff;
my $buffer_len = 1024 * 2;
print "\n$nport\n";
recv(_RSOCK, $buff, $buffer_len, 0);
print $buff;
__END__;
mi collego al server che risulta in ascolto se digito "netstat", ma 
quando voglio inviarli dei dati con "nc -u 127.0.0.1 <port>" non sembra 
riceverli e la mia connessione in udp con "nc -u" cade subito...
dove sbaglio?
Grazie

 Grazie
a me il tuo codice funziona bene su Linux. nel senso che netcat
con -u manda un datagramma ogni linea e quindi, dato che la recv
non e' in un ciclo, ricevo la prima linea e poi in programma
arriva a __END__;
Funziona come mi aspettavo.
dovresti vedere il output la prima linea inserita in nc siche che
termimi con \n sia che termino con EOF.
per quanto riguarda la "connessione", saprai quanto e' improprio
questo termine in contesti di protocolli connectionless come UDP.
con -u netcat manda pacchetti a localhost a quella porta SENZA
aver instaurato alcunche' di preliminare con il server.
se metti recv in un ciclo dovresti vedere tutto, ma attento:
per l' output usa syswrite STDOUT, $buff oppure metti $| = 1;
(autoflush) altrimenti ti sembra non funzionare perche'
l' output bufferizzato della print non avviene subito.
ciao
Roberto
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 l' output bufferizzato della print non avviene subito.
proprio di questo volevo chiederti, se metto recv dentro una while() non 
sembra funzionarmi lo script:
Varire istanze di reader.cgi sono in ascolto in udp su una porta 
assegnata al momento:
### READER
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
$| = 1;
socket(my $fh, PF_INET, SOCK_DGRAM, getprotobyname("udp"));
my $ipaddr   = inet_aton("127.0.0.1");
my $portaddr = sockaddr_in(0, $ipaddr);
bind($fh, $portaddr);
my ( $nport, $naddr );
($nport, $naddr) = sockaddr_in(getsockname($fh));
open( my $fd, ">>listeners.txt");
print $fd "$nport\n";
close($fd);
my $buff;
my $buffer_len = 1024 * 2;
syswrite STDOUT, "Content-type: text/plain\n\n";
syswrite STDOUT, "Listening...\n\n";
# main radio loop
open(_KK, ">data.txt");
recv($fh, $buff, $buffer_len, 0);
   syswrite STDOUT, $buff;
   syswrite _KK, $buff;
close(_KK);
__END__;
Send manda una stringa in localhost a delle specifiche porte:
## SEND
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use CGI::Carp qw(fatalsToBrowser);
my @listeners = &getlist();
&setup();
foreach ( @listeners )
{
   chomp($_);
   &udpsend("127.0.0.1", $_, "Hello world!");
}
print "Content-type: text/plain\n\n";
print "ok!\n";
# create a generic udp socket
sub setup() {
   socket(_SSOCK, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die 
"socket: $!";
}
# send an udp packet: [host], [port], [data] - 1 error, 0 ok
sub udpsend {
 
   my $HOSTNAME = $_[0];
   my $PORTNO   = $_[1];
   my $MSG       = $_[2];
 
   my $ipaddr   = inet_aton($HOSTNAME);
   my $portaddr = sockaddr_in($PORTNO, $ipaddr);
   send(_SSOCK, $MSG, 0, $portaddr) == length($MSG) or return 1;
   return 0;
}
# get entire port list
sub getlist {
   my @listeners;
   if ( -e "listeners.txt" )
   {
      open(_LIST, "<listeners.txt");
      @listeners = <_LIST>;
      close(_LIST);
   }
 
   return @listeners;
}
__END__;
non riesco ad avere l'output "live" ma per dimostrare che i dati 
arrivano in diretta ad ogni ciclo while() di recv salvo su file quello 
che riceve...e infatti il file viene scritto ma sul browser no!
ho provato sia con syswrite e con $|++; ma niente da fare...
cosa sbaglio??
Grazie

 sembra funzionarmi lo script:
nemmeno questo tipo di script mi funziona:
#!/usr/bin/perl
use strict;
use warnings;
use Socket qw(:DEFAULT :crlf);
$|=1;
syswrite STDOUT, "Content-type: text/plain".$CRLF;
syswrite STDOUT, "Content-Length: 999999999999".$CRLF;
syswrite STDOUT, "Cache-Control: no-cahe".$CRLF;
syswrite STDOUT, "Connection: close".$CRLF;
syswrite STDOUT, "Expires: Sat, 22 Apr 2000 22:22:22 GMT".$CRLF;
syswrite STDOUT, $CRLF;
while(1)
{
   syswrite STDOUT, "Hello World!".$CRLF;
   sleep 1;
}

 Grazie
Mi sembra che a questo stadio di sviluppo il codice debba mandare
un solo datagramma a tutte le istanze di ricevitori attivi, ognuno
con la sua porta random giusto? Successivamente sara' uno stream?
E' probabile che il problema sia ancora la bufferizzazione, ma ad un
altro stadio. Non posso essere sicuro. Suggerisco delle prove:
se la bufferizzazione e' con la PIPE verso il server http (apache??)
puoi provare a cambiare il content-type da text/plain a un altro
tipo mime, piu' adatto alle trasmissioni multimediali. come ad esempio
verrebbe trasmesso un mp3 o un movie. non so' quali siano, ma trovarli con
delle prove con telnet alla porta 80 e GET /file.mp3 non dovrebbe essere
difficile. A quel punto c' e' da sperare che il server http abbia la
cortesia pi ritrasmettere immediatamente senza alcuna bufferizzazione.
Se poi il server e' autoprodotto (conoscendoti ormai... :) ) dovrai
intervenire in quei punti.
un' avvertenza che per ora non serve, ma servira':
se mandi un datagramma a un socket non piu' in ascolto (il reader e'
terminato) si riceve indietro un ICMP di PORTA NON PRONTA e se non
droppato da firewall, scatena un segnal al processo trasmittente
(forse il solito SIGPIPE) che se non intercettato trmina il processo.
se fai nc -u localhost 4000 e mandi una linea con porta 4000 non occupate
vedrai nc terminare, se invece c' e' un consumatore, non termina.
quindi dovrai anche gestire il segnal di ritorno, altrimenti uno dei
reader puo' causare un DoS a tutti gli altri facendo terminare SENDER
semplicemente chiudendo la porta.
Per ora mi sento solo di consigliare questo visto che tutto mi pare
apparentemente in ordine.
Ciao
Roberto.


 $|=1;


con maggior convinzione ribadisco quanto detto pochi secondi fa' :)
bufferizzazione tra CGI e server.
forse un content-type diverso risolverebbe.
Ciao.
Roberto.


 apparentemente in ordine.
grazie di tutto e complimenti per le tue conoscenze in ambito

 forse un content-type diverso risolverebbe.
un'altra domanda magari poco attinete: se uno script invia 10k/s di dati 
e un altro script li riceve a 1k/s (ovvero read $buff, 1024) come viene 
gestito il buffer? vengono persi i dati? oppure si ingigantisce??
grazie