关于WebClient超时问题
来源:互联网 发布:石材效果图软件 编辑:程序博客网 时间:2024/06/04 17:50
在用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)使用WebClient.UploadStringAsync (Uri, String, String, Object)这个方法,第三个参数可以存放自定义数据
然后在回调函数中从 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(0, 0, 10);
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(0, 0, 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);
{
/// <summary>
/// 时间到事件
/// </summary>
public event TimeoutCaller TimeOver;
/// <summary>
/// 开始时间
/// </summary>
private DateTime _startTime;
private TimeSpan _timeout = new TimeSpan(0, 0, 10);
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(0, 0, 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();//取消下载
}
}
{
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
阅读全文
0 0
- 关于WebClient超时问题
- WebClient的超时问题及解决
- WebClient的超时问题及解决
- WebClient的超时问题及解决
- WebClient的超时问题及解决
- 用HttpWebRequest代替WebClient解决POST超时问题
- C#用WebClient下载File时操作超时的问题
- C#用WebClient下载File时操作超时的问题
- 关于WebClient的遇到的问题
- 利用HttpURLConnection和WebClient发布REST风格的WebService客户端(解决超时问题)
- 关于Session超时、丢失问题
- 关于gfs超时问题总结
- 关于启动超时的问题
- WP7 webclient cache 问题
- WebClient的使用问题
- 关于WebService的操作超时问题
- 关于SQLServer数据库老是超时的问题
- 关于Extjs异步session超时问题处理
- 16秋第二次作业
- 用C语言实现三子棋小游戏
- BZOJ 3107 [cqoi 2013] DP 解题报告
- 每日一练(20171020)
- linux 系统下Tomcat 开启关闭
- 关于WebClient超时问题
- MySql的使用心得
- C++中##(两个井号)和#(一个井号)用法
- LeetCode 70 Climbing Stairs
- UITableView的基本使用 cell的单选和多选
- Html5 video 标签中视频有声音没画面问题解决过程
- Oculus Go 开发者版本开放索取,下个月设备开始配送
- php trait
- 构造函数