System.Net.FtpClient.FileExists零星失败



我正在尝试使用System.Net。

运行下面的代码,似乎即使IsConnected返回true,直接调用FileExists()调用Connect()(这意味着在调用之间丢失了连接?)。然而,由于Connect()有时会失败,这也会导致FileExists()失败(失败意味着它会抛出Connection refused)。

我的代码有什么问题吗?这是可以预期的,即我是否应该准备好重试我用FtpClient实例做的一切?是否有任何标志可以设置为自动重试?

string myPath = ..;
string myTempPath = myPath+".tmp";
_client = GetClient(_ioc, false);
var _stream = _client.OpenWrite(myTempPath);
//write to stream
_stream.Close();
Android.Util.Log.Debug("NETFTP", "connected: " + _client.IsConnected.ToString()); //always outputs true
if (_client.FileExists(myPath) //sporadically throws, see below
    _client.DeleteFile(myPath);

其中GetClient()被实现为使用我自定义的"retry-loop"来处理零星的连接失败。

private static T DoInRetryLoop<T>(Func<T> func)
{
    double timeout = 30.0;
    double timePerRequest = 1.0;
    var startTime = DateTime.Now;
    while (true)
    {
        var attemptStartTime = DateTime.Now;
        try
        {
            return func();
        }
        catch (System.Net.Sockets.SocketException e)
        {
            if ((e.ErrorCode != 10061) || (DateTime.Now > startTime.AddSeconds(timeout)))
            {
                throw;
            }
            double secondsSinceAttemptStart = (DateTime.Now - attemptStartTime).TotalSeconds;
            if (secondsSinceAttemptStart < timePerRequest)
            {
                Thread.Sleep(TimeSpan.FromSeconds(timePerRequest - secondsSinceAttemptStart));
            }
        }
    }       
}
internal FtpClient GetClient(IOConnectionInfo ioc)
{
    FtpClient client = new FtpClient();
    if ((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
        client.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
    else
        client.Credentials = new NetworkCredential("anonymous", ""); 
    Uri uri = IocPathToUri(ioc.Path);
    client.Host = uri.Host;
    if (!uri.IsDefaultPort)
        client.Port = uri.Port;
    client.EnableThreadSafeDataConnections = false;
    client.EncryptionMode = ConnectionSettings.FromIoc(ioc).EncryptionMode;
    Func<FtpClient> connect = () =>
    {
        client.Connect();
        return client;
    };
    return DoInRetryLoop(connect);
}

这是偶尔出现的例外:

System.Net.Sockets.SocketException : Connection refused
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.Sockets.SocketAsyncResult.CheckIfThrowDelayedException () [0x00017] in /Users/builder/data/lanes/3540/1cf254db/source/mono/mcs/class/System/System.Net.Sockets/SocketAsyncResult.cs:127 
          at System.Net.Sockets.SocketAsyncResult.CheckIfThrowDelayedException () [0x00017] in /Users/builder/data/lanes/3540/1cf254db/source/mono/mcs/class/System/System.Net.Sockets/SocketAsyncResult.cs:127 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.Sockets.Socket.EndConnect (IAsyncResult result) [0x0002f] in /Users/builder/data/lanes/3540/1cf254db/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:1593 
          at System.Net.Sockets.Socket.EndConnect (IAsyncResult result) [0x0002f] in /Users/builder/data/lanes/3540/1cf254db/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:1593 
          at System.Net.FtpClient.FtpSocketStream.Connect (System.String host, Int32 port, FtpIpVersion ipVersions) [0x0011a] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpSocketStream.cs:611 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpSocketStream.Connect (System.String host, Int32 port, FtpIpVersion ipVersions) [0x0011a] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpSocketStream.cs:611 
10-24 13:08:07.487 I/mono-stdout(24073):          at (wrapper remoting-invoke-with-check) System.Net.FtpClient.FtpSocketStream:Connect (string,int,System.Net.FtpClient.FtpIpVersion)
          at (wrapper remoting-invoke-with-check) System.Net.FtpClient.FtpSocketStream:Connect (string,int,System.Net.FtpClient.FtpIpVersion)
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.Connect () [0x000ce] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:807 
          at System.Net.FtpClient.FtpClient.Connect () [0x000ce] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:807 
          at System.Net.FtpClient.FtpClient.Execute (System.String command) [0x00136] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:735 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.Execute (System.String command) [0x00136] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:735 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.Execute (System.String command, System.Object[] args) [0x00001] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:694 
          at System.Net.FtpClient.FtpClient.Execute (System.String command, System.Object[] args) [0x00001] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:694 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.DirectoryExists (System.String path) [0x0005d] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2679 
          at System.Net.FtpClient.FtpClient.DirectoryExists (System.String path) [0x0005d] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2679 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.FileExists (System.String path, FtpListOption options) [0x0001c] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2751 
10-24 13:08:07.487 I/mono-stdout(24073):          at System.Net.FtpClient.FtpClient.FileExists (System.String path) [0x00001] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2733 
          at System.Net.FtpClient.FtpClient.FileExists (System.String path, FtpListOption options) [0x0001c] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2751 
          at System.Net.FtpClient.FtpClient.FileExists (System.String path) [0x00001] in [my source folder]src
etftpandroidSystem.Net.FtpClientFtpClient.cs:2733 

原来,FtpClient正在重新连接,由于一些意想不到的响应,从客户端触发重新连接,因为"陈旧的数据"。我的解决方案是从FtpClient中派生我自己的类,该类使用问题中发布的DoInRetryLoop覆盖Connect()方法。

不幸的是,这只适用于EnableThreadSafeDataConnections=false或覆盖"CloneConnection"方法。后者要求我把它变成虚拟的

相关内容

  • 没有找到相关文章

最新更新