设为首页 收藏本站
查看: 2276|回复: 0

[经验分享] FTP 超时检测 ,C# 函数运行时超时功能改进

[复制链接]

尚未签到

发表于 2015-11-6 10:53:18 | 显示全部楼层 |阅读模式
  

最近频繁操作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的代码如下:

//创建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=&quot;_action&quot;></param>
/// <param name=&quot;_timeout&quot;></param>
public FuncTimeout(EventNeedRun _action, int _timeout)
{
FunctionNeedRun = _action;
timeout = _timeout;
}
/// <summary>
/// 回调函数
/// </summary>
/// <param name=&quot;ar&quot;></param>
public void MyAsyncCallback(IAsyncResult ar)
{
//isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。
if (isGetSignal == false)
{
Console.WriteLine(&quot;放弃执行回调函数&quot;);
Thread.CurrentThread.Abort();
}
else
{
Console.WriteLine(&quot;调用回调函数&quot;);
}
}
/// <summary>
/// 调用函数
/// </summary>
/// <param name=&quot;param1&quot;></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(&quot;函数运行完毕,收到设置信号,异步执行未超时&quot;);
return true;
}
else
{
Console.WriteLine(&quot;没有收到设置信号,异步执行超时&quot;);
return false;
}
}
/// <summary>
/// 把要传进来的方法,和 manu.Set()的方法合并到一个方法体。
/// action方法运行完毕后,设置信号量,以取消阻塞。
/// </summary>
/// <param name=&quot;num&quot;></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=&quot;DomainName&quot;></param>
/// <param name=&quot;FtpUserName&quot;></param>
/// <param name=&quot;FtpUserPwd&quot;></param>
/// <param name=&quot;asyncEventTure&quot;></param>
/// <param name=&quot;asyncEventFalse&quot;></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(&quot;true&quot;))
asyncEventTure(null, EventArgs.Empty);
else
asyncEventFalse(null, EventArgs.Empty);
}
  
  



外部的调用方式:  


class Program
{
static void Main(string[] args)
{
FtpHelper FtpInstance = new FtpHelper();
string FtpSer = &quot;1.1.1.1&quot;;
string FtpUsr = &quot;xxxx&quot;;
string FtpPass = &quot;xxxx&quot;;
FtpInstance.CheckFtp(FtpSer, FtpUsr, FtpPass, returnTrue, returnFalse,8);
Console.ReadLine();
}

public static void returnTrue(object sender,EventArgs e)
{
Console.WriteLine(&quot;returnTrue&quot;);
}
public static void returnFalse(object sender, EventArgs e)
{
Console.WriteLine(&quot;returnFalse&quot;);
}
}
  

版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-135811-1-1.html 上篇帖子: VC实现FTP定时上传文件的实现 下篇帖子: 实验三 FTP协议分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表