博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于WebClient超时问题
阅读量:4057 次
发布时间:2019-05-25

本文共 6190 字,大约阅读时间需要 20 分钟。

在用C#实现一个Http消息推送时,用了WebClient.UpdateString,结果发现该函数在http消息没有返回时会被阻塞。

经测试,阻塞超时是100秒。如果使用默认超时,将会大大影响推送效率,经检索资料,发现WebClient类没有超时设置。

这里查到有两种方案解决。

方案1

 重写WebClient类,增加超时设置,实现起来还是比较简单

public class WebClientEx : WebClient {     public int Timeout {get; set;}     protected override WebRequest GetWebRequest(Uri address)     {        var request = base.GetWebRequest(address);        request.Timeout = Timeout;        return request;     } }
使用

var myClient = new WebClientEx(); myClient.Timeout = 900000 // Daft timeout period myClient.UploadData(myUri, myData);

方案2

使用异步方法 WebClient.UploadStringAsync (Uri, String) 

此方法的缺点是,一旦调用失败,无法直接获取调用的url,但也很容易解决,有两个办法

1)使用这个方法,第三个参数可以存放自定义数据

然后在回调函数中从 e.UserState中获取;

2)同方案1中重写WebClient类,并添加成员变量m_url,调用时自己保存相关信息,等进入回调函数时可以使用。

相关代码:

private static void UploadStringCallback2(Object sender, UploadStringCompletedEventArgs e)        {            //string reply = (string)e.Result; 发生异常时Result是null,正常时是返回信息            WebClientEx wc = (WebClientEx)sender;            string str = wc.GetRequestURL();            string strlog = e.UserState.ToString();            strlog = e.Error.ToString();            }        }        public class WebClientEx : WebClient        {            public string m_strURL;            public int Timeout { get; set; }            protected override WebRequest GetWebRequest(Uri address)            {                var request = base.GetWebRequest(address);                request.Timeout = Timeout;                m_strURL = address.OriginalString;                return request;            }            public string GetRequestURL()            {                return m_strURL;            }        }//===使用WebClientEx wc = new WebClientEx();            //WebClient wc = new WebClientEx();            //wc.Timeout = 3000;            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");//可以post提交            wc.Encoding = Encoding.UTF8;            //string[] pinfo = ConfigurationManager.AppSettings["EnableProxy"].Split('|');            //if (pinfo[0].ToLower() == "true")            //{            //	wc.Proxy = new WebProxy(pinfo[1], int.Parse(pinfo[2]));            //}            string postData = "a=12345&b=abcde";            string m_url = "http://localhost:16910/testpost.ashx";            wc.m_strURL = m_url;            string result = "";            Stopwatch timer = new Stopwatch();            wc.UploadStringCompleted += new UploadStringCompletedEventHandler(UploadStringCallback2);            timer.Start();            try            {                wc.UploadStringAsync(new Uri(m_url), "POST", postData, (object)m_url);                //wc.UploadString(m_url, postData);            }            catch (System.Exception ex)            {                result = ex.Message;            }            timer.Stop();            result +=" use:" +(timer.ElapsedMilliseconds / 1000).ToString();

另,在使用异步下载时,有朋友说网络中断会导致卡死,并给了解决方案,贴在这里备用

创建计时器监视响应情况,过期则取消下载

      

    
public
 
class
 Calculagraph
    
{

        
/// <summary>
        
/// 时间到事件
        
/// </summary>

        public event TimeoutCaller TimeOver;

        
/// <summary>
        
/// 开始时间
        
/// </summary>

        private DateTime _startTime;
        
private TimeSpan _timeout = new TimeSpan(0010);
        
private bool _hasStarted = false;
        
object _userdata;

        
/// <summary>
        
/// 计时器构造方法
        
/// </summary>
        
/// <param name="userdata">计时结束时回调的用户数据</param>

        public Calculagraph(object userdata)
        
{

            TimeOver 
+= new TimeoutCaller(OnTimeOver);
            _userdata 
= userdata;
        }


        
/// <summary>
        
/// 超时退出
        
/// </summary>
        
/// <param name="userdata"></param>

        public virtual void OnTimeOver(object userdata)
        
{

            Stop();
        }


        
/// <summary>
        
/// 过期时间(秒)
        
/// </summary>

        public int Timeout
        
{

            
get
            
{

                
return _timeout.Seconds;
            }

            
set
            
{

                
if (value <= 0)
                    
return;
                _timeout 
= new TimeSpan(00, value);
            }

        }


        
/// <summary>
        
/// 是否已经开始计时
        
/// </summary>

        public bool HasStarted
        
{

            
get
            
{

                
return _hasStarted;
            }

        }


        
/// <summary>
        
/// 开始计时
        
/// </summary>

        public void Start()
        
{

            Reset();
            _hasStarted 
= true;
            Thread th 
= new Thread(WaitCall);
            th.IsBackground 
= true;
            th.Start();
        }


        
/// <summary>
        
/// 重置
        
/// </summary>

        public void Reset()
        
{

            _startTime 
= DateTime.Now;
        }


        
/// <summary>
        
/// 停止计时
        
/// </summary>

        public void Stop()
        
{

            _hasStarted 
= false;
        }


        
/// <summary>
        
/// 检查是否过期
        
/// </summary>
        
/// <returns></returns>

        private bool checkTimeout()
        
{

            
return (DateTime.Now - _startTime).Seconds >= Timeout;
        }


        
private void WaitCall()
        
{

            
try
            
{

                
//循环检测是否过期
                while (_hasStarted && !checkTimeout())
                
{

                    Thread.Sleep(
1000);
                }

                
if (TimeOver != null)
                    TimeOver(_userdata);
            }

            
catch (Exception)
            
{

                Stop();
            }

        }

    }


    
/// <summary>
    
/// 过期时回调委托
    
/// </summary>
    
/// <param name="userdata"></param>

    
public
 
delegate
 
void
 TimeoutCaller(
object
 userdata);

 

      

    
public
 
class
 CNNWebClient : WebClient
    
{


        
private Calculagraph _timer;
        
private int _timeOut = 10;

        
/// <summary>
        
/// 过期时间
        
/// </summary>

        public int Timeout
        
{

            
get
            
{

                
return _timeOut;
            }

            
set
            
{

                
if (value <= 0)
                    _timeOut 
= 10;
                _timeOut 
= value;
            }

        }


        
/// <summary>
        
/// 重写GetWebRequest,添加WebRequest对象超时时间
        
/// </summary>
        
/// <param name="address"></param>
        
/// <returns></returns>

        protected override WebRequest GetWebRequest(Uri address)
        
{

            HttpWebRequest request 
= (HttpWebRequest)base.GetWebRequest(address);
            request.Timeout 
= 1000 * Timeout;
            request.ReadWriteTimeout 
= 1000 * Timeout;
            
return request;
        }


        
/// <summary>
        
/// 带过期计时的下载
        
/// </summary>

        public void DownloadFileAsyncWithTimeout(Uri address, string fileName, object userToken)
        
{

            
if (_timer == null)
            
{

                _timer 
= new Calculagraph(this);
                _timer.Timeout 
= Timeout;
                _timer.TimeOver 
+= new TimeoutCaller(_timer_TimeOver);
                
this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(CNNWebClient_DownloadProgressChanged);
            }


            DownloadFileAsync(address, fileName, userToken);
            _timer.Start();
        }


        
/// <summary>
        
/// WebClient下载过程事件,接收到数据时引发
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        void CNNWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        
{

            _timer.Reset();
//重置计时器
        }


        
/// <summary>
        
/// 计时器过期
        
/// </summary>
        
/// <param name="userdata"></param>

        void _timer_TimeOver(object userdata)
        
{

            
this.CancelAsync();//取消下载
        }

    }

参考:

https://stackoverflow.com/questions/1237966/how-can-i-change-the-time-limit-for-webclient-uploaddata

http://www.cnblogs.com/heros/archive/2009/07/06/1517997.html

你可能感兴趣的文章
socket编程中select的使用
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
长文干货:如何轻松应对工作中最棘手的13种场景?
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.174 - LeetCode1305 - 合并两个搜索树
查看>>
No.175 - LeetCode1306
查看>>
No.182 - LeetCode1325 - C指针的魅力
查看>>
mysql:sql alter database修改数据库字符集
查看>>
mysql:sql truncate (清除表数据)
查看>>
yuv to rgb 转换失败呀。天呀。谁来帮帮我呀。
查看>>
驱动TFT要SDRAM做为显示缓存
查看>>
使用file查看可执行文件的平台性,x86 or arm ?
查看>>
qt 创建异形窗体
查看>>
简单Linux C线程池
查看>>
内存池
查看>>
linux 驱动开发 头文件
查看>>
ipconfig,ifconfig,iwconfig
查看>>
opensuse12.2 PL2303 minicom
查看>>
网络视频服务器移植
查看>>
Encoding Schemes
查看>>