Delphi 印地错误10038“;“非插座上的插座操作”;在61秒的不活动之后

Delphi 印地错误10038“;“非插座上的插座操作”;在61秒的不活动之后,delphi,ftp,indy,delphi-xe7,indy10,Delphi,Ftp,Indy,Delphi Xe7,Indy10,我想从FTP服务器下载一些大文件(GB)。 第一个文件的下载始终有效。然后,当尝试获取我获取的第二个文件时: “套接字错误#10038。非套接字上的套接字操作。” 错误在“Get”上。“获取”后,我看到这些消息(通过FTP状态事件): 代码如下所示: {pseudo-code} for 1 to AllFiles do begin if Connect2FTP then begin FTP.Get(Name, GzFile, TRUE, FALSE); <

我想从FTP服务器下载一些大文件(GB)。 第一个文件的下载始终有效。然后,当尝试获取我获取的第二个文件时:

“套接字错误#10038。非套接字上的套接字操作。”

错误在“Get”上。“获取”后,我看到这些消息(通过FTP状态事件):

代码如下所示:

{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;
此处的完整代码:(PAS)或此处(ZIP)

我认为在调用“解包”后会出现问题,这需要几分钟的时间

更新:已确认:调用“解包”后出现问题。我取消了电话,一切都很好。在下载之间暂停(睡眠或断点)一段时间(我认为超过60秒)会产生同样的问题


FTP使用多个套接字连接,一个用于命令/响应,另一个用于每次传输

套接字错误最可能的原因是FTP代理/路由器/防火墙处于
TIdFTP
之间,FTP服务器在短时间不活动后关闭命令连接。在
Unpack()
(或手动暂停)期间,命令连接上没有传输任何命令/响应,它处于空闲状态,因此可能会被此类代理/路由器/防火墙上的超时关闭

在传输过程中,命令连接处于空闲状态,在传输完成之前,不会传输任何FTP命令/响应(除非中止传输)。在此期间,FTP不知道的代理/路由器/防火墙可能会过早关闭命令连接

为了避免这种情况,
TIdFTP
有一个
NATKeepAlive
属性,可以在命令连接处于空闲状态时启用TCP保持有效。这通常可以防止过早关闭

但是,如果
NATKeepAlive.UseKeepAlive
为True,则在prgress中没有传输时,
TIdFTP
在命令连接上禁用TCP保持有效
TIdFTP
仅在传输期间使用TCP保持有效,前提是您不会在FTP命令之间执行长时间延迟。如果需要延迟一段时间,请关闭FTP连接,或定期发送FTP命令(例如在计时器/线程中调用
TIdFTP.Noop()

或者,您可以尝试在连接到服务器后手动启用TCP保持有效,并将
NATKeepAlive.UseKeepAlive
设置为False,以便
TIdFTP
不会在每次传输后自动禁用保持有效,例如:

函数Connect2FTP(FTP:TIdFTP;RemoteFolder:string;Log:TRichLog):布尔值;
开始
结果:=FTP.Connected;
如果没有结果的话
开始{我们尚未连接}
FTP.Host:=MyFTP;
FTP.Username:=usr;
FTP.Password:=psw;
尝试
FTP.Connect;
尝试
FTP.ChangeDir(远程文件夹);
//空闲10秒后,每5秒发送一次TCP保持活动
FTP.NATKeepAlive.UseKeepAlive:=False;//默认为False,但以防万一。。。
FTP.Socket.Binding.SetKeepAliveValues(True,10000,5000);
除了
FTP.Disconnect(假);
提高;
结束;
除了
出口
结束;
结果:=真;
结束;
结束;
请注意,虽然大多数平台支持在每个连接的基础上启用TCP保持活动(保持活动是TCP规范的一部分),但设置保持活动间隔是特定于平台的。此时,Indy支持将间隔设置为:

  • 适用于Win32和.NET的Windows 2000+和WinCE 4.x+
  • Linux,当在Kylix中使用Indy时
  • Unix/Linux和NetBSD,当在FreePascal中使用Indy时
否则,将使用操作系统默认间隔,根据操作系统配置,在这种情况下,默认间隔的值可能太大,也可能不太大

此时,除了Windows之外,DelphiFireMonkey中的间隔是不可自定义的


如果特定平台支持设置自定义TCP保持活动时间间隔,但Indy未在
SetKeepAliveValues()
中实现,则可以使用
TIdFTP.Socket.Binding.SetSockOpt()
根据需要手动设置值。许多平台确实支持
TCP_KEEPIDLE
/
TCP_KEEPINTVL
或等效的套接字选项。

这是有争议的。代码没有编译,您已经构成了代码的重要部分。我建议你在这个问题上多花点时间。显然你有问题,但如果你在问题上多下功夫,你会得到更好的帮助。在这里问了290个问题之后,我发现很难相信你不知道怎么做,为什么你需要提供一个答案。啊,现在我看到你还在加,甚至在上面的评论之后。不管怎么说,10038意味着你关闭了套接字,然后试图再次使用它。所以现在你知道该去哪里找了,因为你是唯一一个有重新编译和实际代码的人,我想你需要调试它。好吧,我想一切都好了,使用的套接字也好了,当抛出10038时系统就错了。哇。这是一个很好很有帮助的答案!非常感谢。目前,我“解决”了这个问题,在我把下载的文件都拿到手之前,我不会解包。但很快我就会实施你的一个解决方案。下载后、解包前(仅当解包文件较大时)断开连接显然是最容易的,我认为也是最可靠的。与下载1GB数据所需的时间相比,断开/重新连接所增加的时间微不足道。后续行动:
{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;