2016-11-07 48 views
0

我試圖移動到使用System.Net.FtpClient,但事情沒有按預期工作。System.Net.FtpClient.FileExists零星故障

運行下面的代碼,好像即使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()的使用我的自定義「重試循環」,以喊得零星的連接失敗的實現。

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); 

} 

這是偶爾出現的異常:原來的FtpClient被重新連接

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 
etftpandroid\System.Net.FtpClient\FtpSocketStream.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 
etftpandroid\System.Net.FtpClient\FtpSocketStream.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 
etftpandroid\System.Net.FtpClient\FtpClient.cs:807 
      at System.Net.FtpClient.FtpClient.Connect() [0x000ce] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.cs:807 
      at System.Net.FtpClient.FtpClient.Execute (System.String command) [0x00136] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.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 
etftpandroid\System.Net.FtpClient\FtpClient.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 
etftpandroid\System.Net.FtpClient\FtpClient.cs:694 
      at System.Net.FtpClient.FtpClient.Execute (System.String command, System.Object[] args) [0x00001] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.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 
etftpandroid\System.Net.FtpClient\FtpClient.cs:2679 
      at System.Net.FtpClient.FtpClient.DirectoryExists (System.String path) [0x0005d] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.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 
etftpandroid\System.Net.FtpClient\FtpClient.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 
etftpandroid\System.Net.FtpClient\FtpClient.cs:2733 
      at System.Net.FtpClient.FtpClient.FileExists (System.String path, FtpListOption options) [0x0001c] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.cs:2751 
      at System.Net.FtpClient.FtpClient.FileExists (System.String path) [0x00001] in [my source folder]src 
etftpandroid\System.Net.FtpClient\FtpClient.cs:2733 
+0

向我們顯示日誌文件('FtpTrace.AddListener')。 –

回答

1

由於從觸發,因爲「陳舊數據」的重新連接客戶端的一些意外的響應。我的解決方案是從FtpClient派生我自己的類,它使用問題中發佈的DoInRetryLoop覆蓋Connect()方法。

不幸的是,這隻適用於EnableThreadSafeDataConnections = false或重寫「CloneConnection」方法。後者要求我把它變成虛擬的。