Newsgroup: it.comp.lang.perl
Titolo: Cosa strana fra Net::Ftp e Servizio FTP di IIS

Salve a tutti..
vi racconto qualcosa che ha dell'incredibile!
Ho scritto un programma (in Perl, ovvio) che, fra l'altro, include un
semplice
client FTP per upload e download di un file specifico (nella fattispecie, un
database MDB e delle immagini JPG)
con l'uso di Net::Ftp.
Il problema qual'è?
Eccolo: ho un server in rete basato su win2k e IIS5 sia per il web che x
l'FTP.
Ora, dal mio programma, se faccio l'upload sul mio server, il file viene
caricato regolarmente (lo vedo mentre arrivano i dati)
ma alla fine viene automaGicamente e __stranamente__ cancellato dal server.
Se lo stesso file lo uppo con un client tipo CuteFTP o SmartFTP tutto
funziona come da manuale.
A questo punto verrebbe da pensare che c'è un bug nel mio codice... e invece
no!
Perché se provo a uppare lo stesso file, con lo stesso mio programma, su un
server diverso, sempre basato su Win2k e IIS5
(ho provato con un server di Aruba e uno di 9Net-ave) l'upload funziona bene
e il file non viene cancellato.
Riassumendo:
1. se il programma funziona con i 2 server (Aruba e 9Net) ma non funziona
con il mio server, vuol dire che non è il programma, è il server.
2. se l'upload funziona sul mio server con CuteFTP ma non con il mio
programma vuol dire che non è il server, è il programma.
3. per quanto riguarda il download va tutto bene in tutti i casi.
Giusto per... incollo qui la parte di codice che esegue l'upload.
Da considerare che è un applicazione Win32::GUI.
Alcuni comandi come "alert", "confirm", "info", "get_ini", "openPB" sono
altre subs.
Che ne pensate?? Cosa potrebbe creare questo strano miracolo informatico ??
::guido::
<code>
sub putRemoteDbBtn_Click {
 return alert("Nessun database aperto.") unless $db;
 return alert("Specificare il server a cui collegarsi") unless
$mainWin->{'server'}->Text();
 return alert("Digitare il nome utente") unless
$mainWin->{'username'}->Text();
 return alert("Digitare la password") unless $mainWin->{'password'}->Text();
 my $LocalDbFile = get_ini("Local_DB");
 my $LocalFileSize = -s $LocalDbFile;
 return alert("Impossibile trovare il database locale.") unless
$LocalFileSize;
 my $RemoteDB = get_ini("Remote_DB_File");
 return alert("Impostare il nome del database remoto\nnella finestra di
configurazione.") unless $RemoteDB;
 $RemoteDB =~ /(.+)\/(.+)/;
 my $RemoteDir = $1; my $RemoteFile = $2;
 return unless confirm("Aggiornare il database
remoto?\n\n\"$RemoteDB\"\nVerrà sostituito con il file\n\"$LocalDbFile\"");
 my $ThereArePhotos; foreach (values %Fotografie) { $_ and $ThereArePhotos =
1 }
 $ThereArePhotos and my $UploadImagesToo = confirm("Effettuare anche
l'upload delle immagini?");
 openPB("Upload del file $RemoteDB");
 $progressWin->{'pbLabel2'}->Text("Collegamento al server in corso...");
 my $FTP = Net::FTP->new(
  $mainWin->{'server'}->Text(),
  Debug => 0,
  BlockSize => 1024,
  Passive => 1,
  Timeout => 15,
 ) or do {
  closePB();
  return alert("Impossibile collegarsi al server remoto.\nControllare che il
nome del server\nsia stato digitato correttamente.");
 };
 $progressWin->{'pbLabel2'}->Text("Autenticazione in corso...");
 $FTP->login($mainWin->{'username'}->Text(), $mainWin->{'password'}->Text())
or do {
  $FTP->quit if $FTP;
  closePB();
  return alert("Impossibile collegarsi al server remoto.\nControllare
Username e Password.");
 };
 #$FTP->pwd() or do {
 # $FTP->quit if $FTP;
 # closePB();
 # return alert("Impossibile stabilire una connessione con il server
remoto\nRiprovare in un secondo momento.");
 #};
 #if (confirm("Procedere con l'upload del database?")) {
  $progressWin->{'pbLabel2'}->Text("Accesso alla directory remota...");
  $FTP->cwd($RemoteDir) or do {
   $FTP->quit if $FTP;
   closePB();
   return alert("Impossibile entrare nella directory
$RemoteDir.\nControllare il nome e il percorso del database remoto\nnella
finestra di configurazione.");
  };
  if (get_ini("Backup_Remote_DB") == 1) {
   $progressWin->{'pbLabel2'}->Text("Backup del vecchio database in
corso...");
   $FTP->rename($RemoteFile, "$RemoteFile.bak");
  }
  $FTP->quot('TYPE', 'I');
  $progressWin->{'pbLabel2'}->Text("Accesso al file remoto...");
  my $conn = $FTP->stor($RemoteFile) or do {
   $FTP->quit if $FTP;
   closePB();
   return alert("Impossibile salvare il file $RemoteFile sul server
remoto.\nControllare il nome e il percorso del database remoto\nnella
finestra di configurazione.");
  };
  my $TotalBytes;
  open($LOCALDB, "$LocalDbFile"); binmode($LOCALDB); binmode STDOUT;
  while (1) {
   last unless my $len = sysread($LOCALDB, my $buf, 1024);
   syswrite($conn, $buf, $len);
   $TotalBytes += $len;
   Win32::GUI::DoEvents();
   my $percent = int(100*$TotalBytes/$LocalFileSize);
   $ProgBar->SetPos($percent);
   $progressWin->{'pbLabel2'}->Text("Completato: $percent% -
$TotalBytes/$LocalFileSize bytes salvati.");
  }
  close($LOCALDB);
  undef $conn;
    ### Un controllo dopo l'upload del database...
   #$progressWin->{'pbLabel2'}->Text("Richiesta di informazioni estese...");
   #my $RemoteFileSize = $FTP->size("$RemoteDir/$RemoteFile") or do {
   # $FTP->quit if $FTP;
   # closePB();
   # return alert("Impossibile ricevere informazioni estese sul file
remoto.");
   #};
    ###
  $progressWin->{'pbLabel2'}->Text("Upload del database completato.");
 #}
 #############################
 ### Upload delle immagini ###
 if ($UploadImagesToo) {
  Win32::Sleep(500);
  openPB("Upload delle immagini in corso...", 1);
  $progressWin->{'pbLabel2'}->Text("Inizio upload delle immagini...");
  $RemoteDir = get_ini("Remote_IMG_Dir");
  $FTP->quot('TYPE', 'A');
  $FTP->cwd($RemoteDir) or do {
   $FTP->quit if $FTP;
   closePB();
   return alert("Impossibile entrare nella directory
$RemoteDir.\nControllare il percorso remoto delle immagini\nnella finestra
di configurazione.");
  };
  foreach my $Key (sort {$Fotografie{$a} <=> $Fotografie{$b}} keys
%Fotografie) {
   my $FotoFile = $Fotografie{$Key};
   if (length($FotoFile)) {
    $FotoFile =~ /(.+)\\(.+)$/; my $RemoteFile = $2;
    openPB("Upload di $FotoFile in corso...", 1);
    my $LocalFileSize = -s $FotoFile;
    $progressWin->{'pbLabel2'}->Text("Richiesta di informazioni estese...");
    $FTP->quot('TYPE', 'A');
    my $RemoteFileSize = $FTP->size("$RemoteDir/$RemoteFile");
    if (!get_ini("Overwrite_IMGS")) {
     if ($RemoteFileSize == $LocalFileSize) {
      next unless confirm("$RemoteFile ($RemoteFileSize bytes)\n\nGià
esistente sul server remoto.\nSovrascrivere?", 48);
     }
    }
    $FTP->quot('TYPE', 'I');
    my $conn = $FTP->stor($RemoteFile) or do {
     next if confirm("Impossibile salvare il file $RemoteFile sul server
remoto.\nE' possibile che ci sia un errore nella configurazione\noppure il
server ha negato l'operazione.\n\nSi desidera continuare con gli altri
files?");
     $FTP->quit if $FTP;
     closePB();
     return alert("Operazione interrotta.");
    };
    my $TotalBytes;
    open LOCALFOTO, $FotoFile; binmode LOCALFOTO; binmode STDOUT;
    while (1) {
     last unless my $len = sysread(LOCALFOTO, my $buf, 1024);
     syswrite($conn, $buf, $len);
     $TotalBytes += $len;
     Win32::GUI::DoEvents();
     my $percent = int(100*$TotalBytes/$LocalFileSize);
     $ProgBar->SetPos($percent);
     $progressWin->{'pbLabel2'}->Text("Completato: $percent% -
$TotalBytes/$LocalFileSize bytes salvati.");
    }
    close LOCALFOTO;
    # un comando a caso giusto per tenere sveglio il server...
    # anzi, per fargli capire che l'upload precedente è finito! :-)
    $FTP->quot('TYPE', 'A');
   }
  }
 }
 $FTP->quit;
 info("Upload completato.");
 return closePB();
}
</code>

 con l'uso di Net::Ftp.
[...]
Non rispondete perché non vi interessa o perché non avete risposte??

Non rispondete perché non vi interessa o perché non avete risposte??
Può darsi che la necessità di leggersi 180 righe di codice abbia
scoraggiato anche qui qualche risposta forse poteva anche averla.
Prova a circoscrivere il problema.
Io, ch me ne intendo assai poco e non penso di avere una risposta, posso
consigliarti di controllare le impostazioni del server in questione, e
quelle del client il cui upload viene accettato.
Ciao.

 quelle del client il cui upload viene accettato.
Per postare qui vuol dire che ho esaurito tutte le ipotesi che mi venivano a
mente
e ho già fatto tutte le prove del caso...
Ora sul NG cerco ulteriori consigli, sicuramente a qualcuno verrà a mente
qualcosa
che io ancora non ho considerato...
A questo punto riassumo il tutto:
Ci sono due client FTP: uno l'ho programmato io in perl con Net::Ftp
(chiamiamolo "Client A") e l'altro è un client normale di quelli free o
commerciali che si trovano in rete (Cute, Smart, ecc... chiamiamolo "Client
B").
Ci sono anche due server, entrambi basati su Windows 2000 e Internet
Information Server 5: uno è il mio, amministrato da me (chiamiamolo "Server
A") e un altro puo' essere quello di Aruba o di 9NetAve (chiamiamolo "Server
B")
Ecco i casi:
"Client A" => "Server A" => KO
"Client B" => "Server A" => OK
"Client A" => "Server B" => OK
Come si puo' notare, i conti non tornano!
Qualche idea?
Guido.

Qualche idea?
Tutte le idee che potevo avere le ho già dette: il punto sta in qualche
configurazione diversa dei server e dei client. I conti possono benissimo
tornare, se si ipotizza che, in fase di "contrattazione" (lo so che il
protocollo FTP non ha una fase di contrattazione, ma un qualche adattamento
fra server e client accade) il server B riesce a soddisfare le richieste
del client A, e il client B quelle del server A, mentre questo non accade
fra A ed A.
Il principio è: tutti gli FTP sono uguali, ma alcuni sono più uguali di
altri. Client A e Server B sono uguali, Client B e server A sono uguali,
Client B e server B sono uguali, Client A e server A sono meno uguali.
Ciao.

...
E perché non usi put invece di metterti in questo pasticcio?
E, nel caso, perché non usi il metodo write fornito dalla classe?
Ciao.

 E, nel caso, perché non usi il metodo write fornito dalla classe?
Inizialmente, usando il metodo write della classe avevo un altro problema:
al file salvato sul server
mancava qualche byte rispetto al file locale, infatti ri-scaricandolo e
aprendolo con Access risultava
corrotto. Questo è un problema che ho trovato comune a tanti utilizzatori di
Net::Ftp e ne deduco che
spesso è dovuto alle differenze di filesystem fra il client (x esempio
Win98, FAT32)
e il server (x esempio Win2000, NTFS). Stesso problema anche per il
download.
Guido.

infatti ri-scaricandolo e aprendolo con Access risultava corrotto.
Peccato che il metodo write della classe, per il tipo "I", non faccia altro
che usare syswrite per scrivere sulla connessione, senza alcuna
trasformazione dei dati, esattamente come fai tu. Ad occhio, mi verrebbe da
dire che lo fa in un modo forse anche un po' più intelligente, assicurandosi
che il server sia pronto a ricevere, ecc.
In ogni caso, con accortezza non minore, sicché se qualcosa va male con
write, è assai improbabile che tu riesca a mettere a posto le cose
replicandone il medesimo comportamento.
Ciao.