Consistent FTP timeout in a scheduled windows serv

2019-04-14 03:40发布

问题:

I am having problem with ftp, in a windows service. I have scheduled a job to sent files through the ftp. Once in a while i'm having timeout (frequency once a week or maybe once a month), and it continues till i restart my windows service.

System.Net.WebException: The operation has timed out.

I'm handling the exception and in finally i close any opened ftp sessions.

try
        {
            string uri = String.Format("ftp://{0}/{1}/{2}", server, download, file);
            Uri serverUri = new Uri(uri);
            if (serverUri.Scheme != Uri.UriSchemeFtp)
            {
                return;
            }
            FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
            reqFTP.Credentials = new NetworkCredential(username, password);
            reqFTP.KeepAlive = false;
            reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
            reqFTP.EnableSsl = false;
            reqFTP.Proxy = null;
            reqFTP.UsePassive = true;
            reqFTP.Timeout = Settings.Default.TimeOut;
            reqFTP.ReadWriteTimeout = Settings.Default.TimeOut;

            response = (FtpWebResponse)reqFTP.GetResponse();
            responseStream = response.GetResponseStream();

            using (FileStream writeStream = new FileStream(path + file, FileMode.Create))
            {
                int Length = 10240;
                Byte[] buffer = new Byte[Length];
                int bytesRead = responseStream.Read(buffer, 0, Length);
                while (bytesRead > 0)
                {
                    writeStream.Write(buffer, 0, bytesRead);
                    bytesRead = responseStream.Read(buffer, 0, Length);
                }
            }

            response.Close();
        }
        catch (WebException wEx)
        {
            LogDatabase.WriteLog("Download File", wEx.ToString(), "Download File");
        }
        finally
        {
            if (response != null)
            {
                response.Close();
            }
            if (responseStream != null)
            {
                responseStream.Close();
            }
        }

Any ideas ?

thnx in advance.

回答1:

Why can't you put this all in a loop? Then, if you have an error, the loop just goes back and tries again.

Also, why have you set the KeepAlive option to false?

I played around with this for a short while and put it into a class so I could see it better, but did not do any testing on it. My class does the FTP call in a background thread, which is certainly something you'd want to do if you wanted to be able to communicate with this at all.

I certainly give no guarantee that this will work without at least a few glitches!

class FtpRequests {

  private const int BUF_SIZE = 10240;
  private const string PASSWORD = "password";
  private const string USERNAME = "username";
  private const string SERVER = "yourserver.com";
  private string path;

  public FtpRequests() {
    Cancel = false;
    path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
  }

  public bool Cancel { get; set; }

  public bool Complete { get; set; }

  public Thread Thread1 { get; set; }

  public int Timeout { get; set; }

  public int ReadWriteTimeout { get; set; }

  public void StartFtpDownload(string download, string file) {
    string objString = string.Format("{0};{1}", download, file);
    Thread1 = new Thread(startFtpThread);
    Thread1.Name = string.Format("{0} download", file);
    Thread1.IsBackground = true;
    Thread1.Start(objString);
  }

  private void startFtpThread(object obj) {
    Complete = false;
    string objString = obj.ToString();
    string[] split = objString.Split(';');
    string download = split[0];
    string file = split[1];
    do {
      try {
        string uri = String.Format("ftp://{0}/{1}/{2}", SERVER, download, file);
        Uri serverUri = new Uri(uri);
        if (serverUri.Scheme != Uri.UriSchemeFtp) {
          Cancel = true;
          return;
        }
        FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
        reqFTP.Credentials = new NetworkCredential(USERNAME, PASSWORD);
        reqFTP.KeepAlive = true;
        reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
        reqFTP.EnableSsl = false;
        reqFTP.Proxy = null;
        reqFTP.UsePassive = true;
        reqFTP.Timeout = Timeout;
        reqFTP.ReadWriteTimeout = ReadWriteTimeout;
        using (FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse()) {
          using (Stream responseStream = response.GetResponseStream()) {
            using (FileStream writeStream = new FileStream(path + file, FileMode.Create)) {
              Byte[] buffer = new Byte[BUF_SIZE];
              int bytesRead = responseStream.Read(buffer, 0, BUF_SIZE);
              while (0 < bytesRead) {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = responseStream.Read(buffer, 0, BUF_SIZE);
              }
            }
            responseStream.Close();
          }
          response.Close();
          Complete = true;
        }
      } catch (WebException wEx) {
        LogDatabase.WriteLog("Download File", wEx.ToString(), "Download File");
      }
    } while (!Cancel && !Complete);
  }

}