delphi ftp indy delphi-xe7 indy10

delphi - Indy error 10038 "Operación del zócalo en un zócalo" después de 61 segundos de inactividad



ftp delphi-xe7 (1)

FTP utiliza conexiones de socket múltiples, una para comandos / respuestas y conexiones separadas para cada transferencia.

La causa más probable del error de socket es un proxy / enrutador / cortafuegos que no TIdFTP FTP, que se encuentra entre TIdFTP y el servidor FTP está cerrando la conexión de comando después de un breve período de inactividad. Durante el Unpack() (o la pausa manual), no se transmiten comandos / respuestas en la conexión de comando, está inactiva y, por lo tanto, está sujeta a ser cerrada por un tiempo de espera en dicho proxy / enrutador / cortafuegos.

Durante una transferencia, la conexión de comando permanece inactiva, no se transmiten comandos / respuestas de FTP (a menos que se cancele la transferencia), hasta que se complete la transferencia. Un proxy / enrutador / cortafuegos que no conozca el FTP puede cerrar prematuramente la conexión de comando durante este tiempo.

Para evitar eso, TIdFTP tiene una propiedad NATKeepAlive que puede habilitar TCP keep-alives en la conexión de comando mientras está inactivo. Esto generalmente evita cierres prematuros.

Sin embargo, cuando no hay transferencia en curso, TIdFTP desactiva TCP-keep-alives en la conexión de comando si NATKeepAlive.UseKeepAlive es True. TIdFTP utiliza TCP keep-alives solo durante las transferencias, con la suposición de que no va a realizar largas demoras entre los comandos de FTP. Si necesita retrasar por un tiempo, cierre la conexión FTP o envíe un comando FTP a intervalos regulares (como llamar a TIdFTP.Noop() en un temporizador / hilo).

Alternativamente, puede intentar activar manualmente keep-alive TCP después de conectarse al servidor, y establecer NATKeepAlive.UseKeepAlive en False para que TIdFTP no desactive automáticamente las keep-alives después de cada transferencia, por ejemplo:

function Connect2FTP(FTP: TIdFTP; RemoteFolder: string; Log: TRichLog): Boolean; begin Result := FTP.Connected; if not Result then begin { We are not already connected } FTP.Host := MyFTP; FTP.Username:= usr; FTP.Password:= psw; try FTP.Connect; try FTP.ChangeDir(RemoteFolder); // send a TCP keep-alive every 5 seconds after being idle for 10 seconds FTP.NATKeepAlive.UseKeepAlive := False; // False by default, but just in case... FTP.Socket.Binding.SetKeepAliveValues(True, 10000, 5000); except FTP.Disconnect(False); raise; end; except Exit; end; Result := True; end; end;

Tenga en cuenta que, si bien la mayoría de las plataformas admite la activación de TCP keep-alives por conexión (keep-alives son parte de la especificación TCP), la configuración de intervalos de keep-alive es específica de la plataforma. En este momento, Indy admite establecer los intervalos en:

  • Windows 2000+ y WinCE 4.x +, para Win32 y .NET
  • Linux, cuando se usa Indy en Kylix
  • Unix / Linux y NetBSD, cuando Indy se usa en FreePascal.

De lo contrario, se utilizan los intervalos predeterminados del sistema operativo, que pueden ser o no demasiado grandes en esta situación, según la configuración del sistema operativo.

En este momento, los intervalos no se pueden personalizar en Delphi FireMonkey, a excepción de Windows.

Si una plataforma en particular admite la configuración de intervalos TCP keep-alive personalizados, pero Indy no los implementa en SetKeepAliveValues() , puede usar TIdFTP.Socket.Binding.SetSockOpt() lugar para establecer los valores manualmente según sea necesario. Muchas plataformas admiten TCP_KEEPIDLE / TCP_KEEPINTVL o opciones de socket equivalentes.

Quiero descargar algunos archivos grandes (GB) desde un servidor FTP. La descarga del primer archivo siempre funciona. Luego, cuando intento obtener el segundo archivo, obtengo:

"Socket Error # 10038. Operación del zócalo en no zócalo".

El error está en ''Obtener''. Después de ''Obtener'' veo estos mensajes (a través del evento de estado de FTP):

Starting FTP transfer Disconnecting. Disconnected.

El código es así:

{pseudo-code} for 1 to AllFiles do begin if Connect2FTP then begin FTP.Get(Name, GzFile, TRUE, FALSE); <--- Socket operation on non-socket" error (I also get EIdConnClosedGracefully ''Connection Closed Gracefully'' in IDE, F9 will resume execution without problems, but this is OK) Unpack(GzFile); <--- this takes more than 60 seconds end; end; if FTP.Connected then FTP.Disconnect;

-

function Connect2FTP(FTP: TIdFTP; RemoteFolder: string; Log: TRichLog): Boolean; begin Result:= FTP.Connected; if NOT Result then begin { We are already connected } FTP.Host := MyFTP; FTP.Username:= usr; FTP.Password:= psw; TRY FTP.Connect; EXCEPT on E: Exception DO Result:= FTP.Connected; if Result then FTP.ChangeDir(RemoteFolder); end; end;

El código completo aquí: http://pastebin.com/RScj86R8 (PAS) o aquí https://ufile.io/26b54 (ZIP)

Creo que el problema aparece después de llamar a ''Unpack'', que toma unos minutos.

ACTUALIZACIÓN: CONFIRMADO: el problema aparece después de llamar a ''Unpack''. Eliminé la llamada y todo está bien. Pausar (dormir o romper el punto) el programa entre descargas por un tiempo (creo que por más de 60 segundos) creará el mismo problema.