2013-02-20 64 views
2

我構建了一個.NET Mono應用程序,該應用程序每分鐘都會將文本文件上載到服務器。這個應用程序確實需要全天候運行,我正在使用它將.rss提要中的數據傳輸到我們的圖文電視服務器,以便在電視上傳輸。 在我看來,避免崩潰應用程序的最好方法是使用上傳代碼的嘗試,以避免意外的錯誤。Try/Catch沒有捕捉到WebException

它總是運行正常約2天,之後它突然崩潰。我正在尋找原因已經幾個星期,但無法找到它。

我得到的錯誤是:

未處理的異常信息:System.Net.WebException:在System.Net.FtpWebRequest 0:在 System.Net.FtpWebRequest.CheckIfAborted()[0x00000]請求中止.set_Sate(RequestState值) [0x00000]中:0在 System.Net.FtpWebRequest.ProcessRequest(RequestState值)[0x00000] 中:在System.Threading.Thread.StartUnsafe() [0x00000]中:

你的PLOAD代碼線程內運行是:

private static readonly ILog log = LogManager.GetLogger(typeof(PheTextConnector)); 

static String ftp_path = ConfigurationManager.AppSettings["txtServerFTPPath"]; 
static String ip = ConfigurationManager.AppSettings["txtServerIP"]; 
static String username = ConfigurationManager.AppSettings["txtServerUsername"]; 
static String password = ConfigurationManager.AppSettings["txtServerPassword"]; 

public void UploadToTextServer(String filename, String uploadfolder) 
{ 
    try 
    { 
    UploadFile(ip, ftp_path, filename, username, password, uploadfolder); 
    } 
    catch(Exception ex) 
    { 
    log.Error(ex.ToString()); 
    } 
} 

public void UploadFile(string FTPAddress, string directory, string filename, string username, string password, string uploadfolder) 
{ 
    try 
    { 
     FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + FTPAddress + "/" + directory + "/" + Path.GetFileName(filename)); 

     request.Method = WebRequestMethods.Ftp.UploadFile; 
     request.Credentials = new NetworkCredential(username, password); 
     request.UsePassive = true; 
     request.UseBinary = true; 
     request.KeepAlive = true; 

     FileStream fs = File.OpenRead(uploadfolder + "/" + filename); 
     int buffLength = 4096; 
     byte[] buffer = new byte[buffLength]; 
     Stream strm = request.GetRequestStream();     
     int bytesRead = fs.Read(buffer, 0, buffer.Length); 

     while (true) 
     { 
      if (bytesRead == 0) 
      { 
       strm.Close(); 
       fs.Close(); 
       break; 
      } 
      else 
      { 
       strm.Write(buffer, 0, bytesRead); 
       bytesRead = fs.Read(buffer, 0, buffLength); 
      } 
     } 

     FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 
     response.Close(); 
    } 
    catch(Exception ex) 
    { 
     log.Error(ex.ToString()); 
    } 
} 
} 

類調​​用上傳方法的代碼是:

using System; 
using System.IO; 
using System.Threading; 
using log4net; 
using System.Text.RegularExpressions; 
using System.Configuration; 

public class PhecapConnectionMain 
{ 
    private static readonly ILog log = LogManager.GetLogger(typeof(PhecapConnectionMain)); 

private Object thisLock = new Object(); 
private int waitTimeBetweenTxtUpdates = Int32.Parse(ConfigurationManager.AppSettings["txtServerTimeBetweenUpdates"]); 
private String transferDirectory = ConfigurationManager.AppSettings["transferDirectoryName"]; 

public PhecapConnectionMain() 
{ 
    try 
    { 
     log.Debug("Start Phecap Connection"); 

     CreateDirectoryIfNotExists(transferDirectory); 
     FileSystemWatcher _watcher = new FileSystemWatcher(); 
     _watcher.Path = transferDirectory+"/"; 

     _watcher.NotifyFilter = System.IO.NotifyFilters.DirectoryName; 
     _watcher.NotifyFilter = _watcher.NotifyFilter | System.IO.NotifyFilters.FileName; 
     _watcher.NotifyFilter = _watcher.NotifyFilter | System.IO.NotifyFilters.Attributes; 

     _watcher.EnableRaisingEvents = true; 
     _watcher.IncludeSubdirectories = true; 

     _watcher.Created += new FileSystemEventHandler(eventRaised); 
    } 
    catch(Exception ex) 
    { 
     log.Error(ex.ToString()); 
    } 
} 

/// <summary> 
/// Triggered when an event is raised from the folder activity monitoring. 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e">containing all data send from the event that got executed.</param> 
private void eventRaised (object sender, System.IO.FileSystemEventArgs e) 
{ 
    String changedFileName = e.Name; 

    changedFileName = Regex.Replace (changedFileName, @"//", @"//"); 
    changedFileName = String.Format(@"{0}",changedFileName); 

    switch(e.ChangeType) 
    { 
     case WatcherChangeTypes.Created: 
      if(changedFileName.Contains("update.sem")) 
      { 
       Thread thread = new Thread(NewFolderCreatedThread); 
       thread.Start(e); 
      } 
      break; 
     default: 
     break; 
    } 
} 

/// <summary> 
/// Creates a directory if not exists. 
/// </summary> 
/// <param name='folderName'> 
/// Folder name. 
/// </param> 
private void CreateDirectoryIfNotExists(String folderName) 
{ 
    if(Directory.Exists(folderName) == false) 
    { 
     Directory.CreateDirectory(folderName);   
    } 
} 

/// <summary> 
/// News the folder created thread. 
/// </summary> 
/// <param name='parameterObject'> 
/// Parameter object. 
/// </param>/ 
public void NewFolderCreatedThread(object parameterObject) 
{ 
    // Lock object, one thread at a time may upload files 
    lock(thisLock) 
    { 
     try 
     { 
      System.IO.FileSystemEventArgs fileInfo = (System.IO.FileSystemEventArgs) parameterObject;   
      String[] splitted = fileInfo.Name.Split('/'); 
      String directory = transferDirectory+"/"+splitted[splitted.Length-2]+"/"; 

      string [] fileEntries = Directory.GetFiles(directory); 
      PheTextConnector pheTextConnector = new PheTextConnector(); 

      int percentage = 0; 
      double counter = 1; 
      double lengt = fileEntries.Length; 

      foreach(string fName in fileEntries) 
      {    
       String[] tempSplitted = fName.Split('/'); 
       String fileName = tempSplitted[tempSplitted.Length-1]; 

       if(!fileName.Equals("update.sem")) 
       { 
        pheTextConnector.UploadToTextServer(fileName, directory); 
       } 

       double percent = (counter/lengt) * 100.0; 
       percentage = (int) percent; 
       ConsoleFunctions.RenderConsoleProgress(percentage, '\u2590', ConsoleColor.Yellow, "Uploading file " + fileName); 
       counter++; 
      } 

      pheTextConnector.UploadToTextServer("update.sem", directory); 

      Directory.Delete(directory, true); 
      log.Debug("Files are uploaded to server, wait " + waitTimeBetweenTxtUpdates + " milliseconds for releasing lock"); 

      Thread.Sleep(waitTimeBetweenTxtUpdates); 
      log.Debug("Waiting complete... release lock and allow new updates to be uploaded to the server"); 
     } 
     catch(Exception ex) 
     { 
      log.Error(ex.ToString()); 
     } 
    }   
} 
} 

- 編輯:

我提高了UploadMethod使用的語句。並且通過將FTPWebRequest的超時值設置爲100 ms,找到了重現此錯誤的方法。 而不是由try catch捕獲的超時錯誤,應用程序完全崩潰。

using System; 
using System.IO; 
using System.Net; 
using System.Configuration; 
using log4net; 

public class PheTextConnector 
{ 
    private static readonly ILog log = LogManager.GetLogger(typeof(PheTextConnector)); 
    static String ftp_path = ConfigurationManager.AppSettings["txtServerFTPPath"]; 
    static String ip = ConfigurationManager.AppSettings["txtServerIP"]; 
    static String username = ConfigurationManager.AppSettings["txtServerUsername"]; 
    static String password = ConfigurationManager.AppSettings["txtServerPassword"]; 

    public void UploadToTextServer(String filename, String uploadfolder) 
    { 
     try 
     { 
      UploadFile(ip, ftp_path, filename, username, password, uploadfolder); 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
     } 
     catch(Exception ex) 
     { 
      log.Error(ex.ToString()); 
     } 
    } 

    public void UploadFile(string FTPAddress, string directory, string filename, string username, string password, string uploadfolder) 
    { 
    try 
     { 
      FtpWebRequest request = (FtpWebRequest) WebRequest.Create("ftp://" + FTPAddress + "/" + directory + "/" + Path.GetFileName(filename)); 
      request.Method = WebRequestMethods.Ftp.UploadFile; 
      request.Credentials = new NetworkCredential(username, password); 
      request.UsePassive = true; 
      request.UseBinary = true; 
      request.KeepAlive = true; 
      request.Timeout = 100; 

      byte[] buffer = new byte[4096]; 
      using (FileStream fs = File.OpenRead(uploadfolder + "/" + filename)) 
      { 
       using(Stream stream = request.GetRequestStream()) 
       { 
        int bytesRead = fs.Read(buffer, 0, buffer.Length); 
        while (true) 
        { 
         if (bytesRead == 0) 
         { 
          stream.Close(); 
          break; 
         } 
         else 
         { 
          stream.Write(buffer, 0, bytesRead); 
          bytesRead = fs.Read(buffer, 0, 4096); 
         } 
        } 
       } 
      } 
      using(FtpWebResponse response = (FtpWebResponse)request.GetResponse()) 
      { 
       response.Close(); 
      } 

      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
     } 
     catch(Exception ex) 
     { 
      log.Error(ex.ToString()); 
     } 
    } 
} 

System.Net.WebException: Request timed out 
at System.Net.FtpWebRequest.EndGetRequestStream (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
at System.Net.FtpWebRequest.GetRequestStream() [0x00000] in <filename unknown>:0 
at PheTextConnector.UploadFile (System.String FTPAddress, System.String directory, 
System.String filename, System.String username, System.String password, System.String 
uploadfolder) [0x00094] in /svn/WOSTeletekst/WOSTxT/PheCapConnector 
/PheTextConnector.cs:47 

System.Net.WebException: Request aborted 
at System.Net.FtpWebRequest.CheckIfAborted() [0x00000] in <filename unknown>:0 
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename unknown>:0 
at System.Net.FtpWebRequest.UploadData() [0x00000] in <filename unknown>:0 
at System.Net.FtpWebRequest.ProcessMethod() [0x00000] in <filename unknown>:0 
at System.Net.FtpWebRequest.ProcessRequest() [0x00000] in <filename unknown>:0 
+0

Mb你的'log'類沒有初始化?你在'catch {}'塊中得到異常?嘗試調試它,你會看到你在哪裏得到異常。 – Maris 2013-02-20 09:45:39

+0

我沒有插入整個類,* edit *,還插入了其餘的代碼。 – 2013-02-20 09:47:34

+0

如何調試,在哪個字符串中出現錯誤? – Maris 2013-02-20 09:49:07

回答

0

這樣的錯誤真的很難找到。 你說你在一個線程中運行這個函數。所以我想它是從while循環中調用的,而不是Thread.Sleep(1000*60);或者fire and forget。原因可能是該函數在下次調用之前還未完成,或者FtpWebRequest仍未關閉,並且它在不同的上下文中運行並不重要。

我有類似的問題,在這裏你可以嘗試什麼:

1)請FtpWebRequest request全球並檢查它是否在函數調用前還活着。

2)調用的函數結束的垃圾收集器:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

請讓我知道是否可行。

+0

如何檢查請求是否仍然存在?,找不到IsAlive()方法或類似的東西。 – 2013-02-20 10:23:17

+0

@StefanKruijt在函數結束時將其設置爲null並檢查它是否爲null。但先嚐試GC,因爲它前段時間幫助我 – VladL 2013-02-20 10:30:04

+1

我發現了一種通過將FtpWebRequest的超時值設置爲100ms來重現錯誤的方法。應用程序第一次崩潰。這個錯誤也沒有被try catch捕獲。請參閱下面的改進代碼和錯誤。 – 2013-02-20 11:16:59

1

你的電視機可能沒有什麼問題,我的意思是你的代碼。

問題是Mono的FtpWebRequest實現不是很健壯(在FTP會話的各個階段處理超時的能力很差)。我做了類似的案例進行分析,並張貼了我的研究結果有:

Mono for Android/MonoTouch System.Net.WebException: Request aborted

你的情況,雖然不完全相同,指向與Mono的的FtpWebRequest的問題常見的「袋」。