FTP 超时检测 ,C# 函数运行时超时功能改进
2013-06-26 21:11
176 查看
最近频繁操作FTP,但是也频繁遇到一个问题,那就是检测的超时问题,虽然有设定超时时间,但是由于其他原因,会造成这个超时时间根本无法随心定义,主要原因如MSDN描述如下:
Timeout 是进行后续同步请求时使用 GetResponse 方法等待响应以及 GetRequestStream 方法等待流所允许的毫秒数。 Timeout 适用于整个请求和响应,不单独对 GetRequestStream 与 GetResponse 方法调用响应。 如果资源在超时期限内未返回,请求将引发 WebException,并将 Status 属性设置为 WebExceptionStatus.Timeout。
Timeout 属性必须在 GetRequestStream 或 GetResponse 方法被调用之前设置。 在调用 GetRequestStream 或 GetResponse 方法之后更改 Timeout 属性不起任何作用
Timeout 属性对使用 BeginGetResponse 或 BeginGetRequestStream 方法生成的异步请求无效。
警告 在异步请求的情况下,客户端应用程序实现其自己的超时机制。 请参考 BeginGetResponse 方法中的示例。
若要指定在读写操作超时之前等待的时间量,请使用 ReadWriteTimeout 属性。
域名系统 (DNS) 查询可能需要 15 秒返回或超时。 如果您的请求包含要求解析的主机名,并且您将 Timeout 设置为小于 15 秒的值,则在 15 秒或更长时间之后才会引发 WebException 以指示您的请求超时。
原有的访问FTP的代码如下:
这种方案在项目中的体检非常不好,因为凡是超过5秒以上的请求(内网中,5秒数字为估算),基本成功访问的可能性很低了,但是FTP自己的超时机制还是会等待,有时甚至等待20-30秒,结果返回访问失败,这样对于用户来说很是头疼,就连我在测试时也是非常纠结,只能在超过5秒后选择直接关闭DEBUG,但是问题终究需要解决,查阅资料后,发现如下的方式:
ManualResetEvent 类
发送反馈
通知一个或多个正在等待的线程已发生事件。无法继承此类。
命名空间: System.Threading
程序集: mscorlib(在 mscorlib.dll 中)
ManualResetEvent 允许线程通过发信号互相通信。 通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。
当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。 此线程可被视为控制 ManualResetEvent。 调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。 当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。 并释放所有等待线程。
一旦它被终止, ManualResetEvent 将保持终止状态,直到它被手动重置。 即对 WaitOne 的调用将立即返回。
以下代码参考自:http://www.51testing.com/html/71/n-836371.html
参考别人的代码,鉴于我在项目中需要使用的功能,修改封装如下:
检查FTP连通性的参数类如下:
FTP连通性检查方法:
外部的调用方式:
Timeout 是进行后续同步请求时使用 GetResponse 方法等待响应以及 GetRequestStream 方法等待流所允许的毫秒数。 Timeout 适用于整个请求和响应,不单独对 GetRequestStream 与 GetResponse 方法调用响应。 如果资源在超时期限内未返回,请求将引发 WebException,并将 Status 属性设置为 WebExceptionStatus.Timeout。
Timeout 属性必须在 GetRequestStream 或 GetResponse 方法被调用之前设置。 在调用 GetRequestStream 或 GetResponse 方法之后更改 Timeout 属性不起任何作用
Timeout 属性对使用 BeginGetResponse 或 BeginGetRequestStream 方法生成的异步请求无效。
警告 在异步请求的情况下,客户端应用程序实现其自己的超时机制。 请参考 BeginGetResponse 方法中的示例。
若要指定在读写操作超时之前等待的时间量,请使用 ReadWriteTimeout 属性。
域名系统 (DNS) 查询可能需要 15 秒返回或超时。 如果您的请求包含要求解析的主机名,并且您将 Timeout 设置为小于 15 秒的值,则在 15 秒或更长时间之后才会引发 WebException 以指示您的请求超时。
原有的访问FTP的代码如下:
//创建FtpWebRequest对象 FtpWebRequest ftprequest = (FtpWebRequest)WebRequest.Create("ftp://" + DomainName); ftprequest.Timeout = 5000;//设定5秒超时 ftprequest.ReadWriteTimeout = 5000; //域名系统 (DNS) 查询可能需要 15 秒返回或超时。 如果您的请求包含需要解析的主机 //名,并将 Timeout 设置为少于 15 秒的值,则在引发 WebException 以指示您的请求 //超时之前,可能需要 15 秒或更多的时间。
这种方案在项目中的体检非常不好,因为凡是超过5秒以上的请求(内网中,5秒数字为估算),基本成功访问的可能性很低了,但是FTP自己的超时机制还是会等待,有时甚至等待20-30秒,结果返回访问失败,这样对于用户来说很是头疼,就连我在测试时也是非常纠结,只能在超过5秒后选择直接关闭DEBUG,但是问题终究需要解决,查阅资料后,发现如下的方式:
ManualResetEvent 类
发送反馈
通知一个或多个正在等待的线程已发生事件。无法继承此类。
命名空间: System.Threading
程序集: mscorlib(在 mscorlib.dll 中)
ManualResetEvent 允许线程通过发信号互相通信。 通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。
当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。 此线程可被视为控制 ManualResetEvent。 调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。 当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。 并释放所有等待线程。
一旦它被终止, ManualResetEvent 将保持终止状态,直到它被手动重置。 即对 WaitOne 的调用将立即返回。
以下代码参考自:http://www.51testing.com/html/71/n-836371.html
参考别人的代码,鉴于我在项目中需要使用的功能,修改封装如下:
/// <summary> /// 函数运行中超时控制类 /// </summary> public class FuncTimeout { /// <summary> /// 信号量 /// </summary> private ManualResetEvent manu = new ManualResetEvent(false); /// <summary> /// 是否接受到信号 /// </summary> private bool isGetSignal; /// <summary> /// 设置超时时间 /// </summary> private int timeout; public delegate bool EventNeedRun(ITimeOutPara paras); /// <summary> /// 要调用的方法的一个委托 /// </summary> private EventNeedRun FunctionNeedRun; /// <summary> /// 构造函数,传入超时的时间以及运行的方法 /// </summary> /// <param name="_action"></param> /// <param name="_timeout"></param> public FuncTimeout(EventNeedRun _action, int _timeout) { FunctionNeedRun = _action; timeout = _timeout; } /// <summary> /// 回调函数 /// </summary> /// <param name="ar"></param> public void MyAsyncCallback(IAsyncResult ar) { //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。 if (isGetSignal == false) { Console.WriteLine("放弃执行回调函数"); Thread.CurrentThread.Abort(); } else { Console.WriteLine("调用回调函数"); } } /// <summary> /// 调用函数 /// </summary> /// <param name="param1"></param> public bool doAction(ITimeOutPara paras) { EventNeedRun WhatTodo = CombineActionAndManuset; //通过BeginInvoke方法,在线程池上异步的执行方法。 var r = WhatTodo.BeginInvoke(paras, MyAsyncCallback, null); //设置阻塞,如果上述的BeginInvoke方法在timeout之前运行完毕,则manu会收到信号。此时isGetSignal为true。 //如果timeout时间内,还未收到信号,即异步方法还未运行完毕,则isGetSignal为false。 isGetSignal = manu.WaitOne(timeout * 1000); if (isGetSignal == true) { Console.WriteLine("函数运行完毕,收到设置信号,异步执行未超时"); return true; } else { Console.WriteLine("没有收到设置信号,异步执行超时"); return false; } } /// <summary> /// 把要传进来的方法,和 manu.Set()的方法合并到一个方法体。 /// action方法运行完毕后,设置信号量,以取消阻塞。 /// </summary> /// <param name="num"></param> private bool CombineActionAndManuset(ITimeOutPara paras) { bool pass = FunctionNeedRun(paras); manu.Set(); return pass; } } /// <summary> /// 可以借助这个接口进行异步方法的参数传入和传出。 /// </summary> public interface ITimeOutPara { /// <summary> /// 参数集合,顺序不能乱 /// </summary> List<object> Parameters { set; get; } }
检查FTP连通性的参数类如下:
/// <summary> /// 检查FTP连通性,参数 /// </summary> public class CheckFtpPatermeters : ITimeOutPara { public List<object> Parameters { set; get; } public CheckFtpPatermeters(string DomainName, string FtpUserName, string FtpUserPwd) { Parameters = new List<object>(); Parameters.Add(DomainName); Parameters.Add(FtpUserName); Parameters.Add(FtpUserPwd); } }
FTP连通性检查方法:
/// <summary> /// 异步调用FTP验证 /// </summary> /// <param name="DomainName"></param> /// <param name="FtpUserName"></param> /// <param name="FtpUserPwd"></param> /// <param name="asyncEventTure"></param> /// <param name="asyncEventFalse"></param> public void CheckFtp(string DomainName, string FtpUserName, string FtpUserPwd , EventHandler asyncEventTure, EventHandler asyncEventFalse, int timeout) { bool ResultValue = true; CheckFtpPatermeters paras = new CheckFtpPatermeters(DomainName, FtpUserName, FtpUserPwd); try { FuncTimeout time = new FuncTimeout(asyncCheckFtp, timeout); ResultValue = time.doAction(paras); } catch { ResultValue = false; } if (paras.Parameters.Count ==4 && paras.Parameters[3].ToString().Equals("true")) asyncEventTure(null, EventArgs.Empty); else asyncEventFalse(null, EventArgs.Empty); }
外部的调用方式:
class Program { static void Main(string[] args) { FtpHelper FtpInstance = new FtpHelper(); string FtpSer = "1.1.1.1"; string FtpUsr = "xxxx"; string FtpPass = "xxxx"; FtpInstance.CheckFtp(FtpSer, FtpUsr, FtpPass, returnTrue, returnFalse,8); Console.ReadLine(); } public static void returnTrue(object sender,EventArgs e) { Console.WriteLine("returnTrue"); } public static void returnFalse(object sender, EventArgs e) { Console.WriteLine("returnFalse"); } }
相关文章推荐
- C#中,函数运行超时的功能的实现
- C#检测程序重复运行的函数(可以在多用户登录情况下检测)
- C# 给某个方法设定执行超时时间 C#如何控制方法的执行时间,超时则强制退出方法执行 C#函数运行超时则终止执行(任意参数类型及参数个数通用版)
- C#检测应用程序重复启动----函数检测(可以在多用户登录情况下检测)
- PHP常量PHP_SAPI与函数php_sapi_name()简介,PHP运行环境检测
- C#报错“OS加载程序锁内执行托管代码,不要尝试在DllMain或映像初始化函数内运行托管代码”的解决方法。
- C#之使用NotifyIcon实现任务栏托盘菜单,图标闪烁效果及气泡提示 很多程序是只需要后台运行的,甚至不需要自己的应用界面。NotifyIcon提供了程序在任务栏的显示功能 程序下载链接如下
- C# 调用 Emgu.CV 显示RTSP流 + 设置程序运行超时时间
- 检测到LoaderLock,正试图在OS加载程序锁内执行托管代码,不要尝试在DllMain或映像初始化函数内运行托管代码,这样会导致应用程序挂起。
- C# 调用系统“运行”功能
- C# 检测真实的文件类型函数
- C#编写开机自动运行函数
- C# 使用WebRequest 实现FTP常用功能
- c#实现ftp功能
- 前端复习--测试用例如何写,如何检测函数的运行效率。
- SQL实现类似C#的Split()函数的功能
- C#快速检测32位Or64位运行环境
- IsDebuggerPresent() 函数检测进程是否运行在调试器的控制下
- 我用C#调用C编译的dll中有这样一个函数,函数大概的功能就是把数据保存到buf缓冲区中:
- C# 开机检测是否运行某程序的方法