delphi - Indy error 10038 "Socket operation on non-socket" after 61 seconds of inactivity -


i want download large files (gb) ftp server. download of first file works. when trying second file get:

"socket error # 10038. socket operation on non-socket."

the error on 'get'. after 'get' see these messages (via ftp status event):

   starting ftp transfer    disconnecting.    disconnected. 

the code this:

{pseudo-code} 1 allfiles   begin     if connect2ftp      begin      ftp.get(name, gzfile, true, false);  <--- socket operation on non-socket" error (i eidconnclosedgracefully 'connection closed gracefully' in ide, f9 resume execution without problems, ok)      unpack(gzfile); <--- takes more 60 seconds     end;  end; if ftp.connected ftp.disconnect; 

--

function connect2ftp(ftp: tidftp; remotefolder: string; log: trichlog): boolean;       begin  result:= ftp.connected;  if not result   begin         { connected }    ftp.host    := myftp;    ftp.username:= usr;    ftp.password:= psw;     try     ftp.connect;    except     on e: exception     result:= ftp.connected;    if result ftp.changedir(remotefolder);    end; end; 

full code here: http://pastebin.com/rscj86r8 (pas) or here https://ufile.io/26b54 (zip)

i think problem appears after calling 'unpack' takes few minutes.

update: confirmed: problem appears after calling 'unpack'. removed call , fine. pausing (sleep or break point) program between downloads while (i think more 60 sec) create same problem.

enter image description here

ftp uses multiple socket connections, 1 commands/responses, , separate connections each transfer.

the cause of socket error ftp-unaware proxy/router/firewall sitting in between tidftp , ftp server closing command connection after short period of inactivity. during unpack() (or manual pause), no commands/responses being transmitted on command connection, sitting idle, , subject being closed timeout on such proxy/router/firewall.

during transfer, command connection sitting idle, no ftp commands/responses being transmitted on (unless abort transfer), until transfer complete. ftp-unaware proxy/router/firewall may close command connection prematurely during time.

to avoid that, tidftp has natkeepalive property can enable tcp keep-alives on command connection while sitting idle. prevents premature closes.

however, when there no transfer in prgress, tidftp disables tcp keep-alives on command connection if natkeepalive.usekeepalive true. tidftp uses tcp keep-alives during transfers, assumption not going perform long delays in between ftp commands. if need delay awhile, either close ftp connection, or send ftp command @ regular intervals (such calling tidftp.noop() in timer/thread).

alternatively, can try manually enabling tcp keep-alives after connecting server, , set natkeepalive.usekeepalive false tidftp not automatically disable keep-alives after each transfer, eg:

function connect2ftp(ftp: tidftp; remotefolder: string; log: trichlog): boolean;       begin   result := ftp.connected;   if not result   begin         { not connected }     ftp.host    := myftp;     ftp.username:= usr;     ftp.password:= psw;      try       ftp.connect;       try         ftp.changedir(remotefolder);           // send tcp keep-alive every 5 seconds after being idle 10 seconds         ftp.natkeepalive.usekeepalive := false; // false default, in case...         ftp.socket.binding.setkeepalivevalues(true, 10000, 5000);       except         ftp.disconnect(false);         raise;       end;     except       exit;     end;      result := true;   end; end; 

note while platforms support enabling tcp keep-alives on per-connection basis (keep-alives part of tcp spec), setting keep-alive intervals platform-specific. @ time, indy supports setting intervals on:

  • windows 2000+ , wince 4.x+, win32 , .net
  • linux, when indy used in kylix
  • unix/linux , netbsd, when indy used in freepascal.

otherwise, os default intervals used, may or may not large in value situation, depending on os configuration.

at time, intervals not customizable in delphi firemonkey, except windows.

if particular platform supports setting custom tcp keep-alive intervals, indy not implement them in setkeepalivevalues(), can use tidftp.socket.binding.setsockopt() instead set values manually needed. many platforms support tcp_keepidle/tcp_keepintvl or equivalent socket options.


Comments