异步HTtpWebrequest请求,获取html,窗体为什么还会卡死?

大刘0417 2017-04-13 09:30:34
使用异步方式请求数据,在窗体上执行后(在另一个线程循环50次),文本框可以正常获取HTML文本,但每次触发发提取数据结束的事件显示在textbox上时,界面都会卡死一会,(但在htmlHelper_Event_IAsyncReadEnd事件中,如果只写:Textbox1.text+="1",就不会卡),例底是什么原因,求解决办法?

异步请求类(SQLHelper)的代码:
class RequestState
{
const int BUFFER_SIZE = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public HttpWebRequest Request;
public HttpWebResponse Response;
public Stream StreamResponse;
public RequestState()
{
BufferRead = new byte[BUFFER_SIZE];
RequestData = new StringBuilder("");
Request = null;
StreamResponse = null;
}
}

public class HtmlHelper
{
/// <summary>异步请求,读取分块数据事件</summary>
public event Action<string> Event_IAsyncReadDataing;
/// <summary>异步请求,读取分块数据结束事件</summary>
public event Action<string> Event_IAsyncReadEnd;
//如果超时,中断请求
private void TimeoutCallback(object state, bool timeOut)
{
if (timeOut)
{
HttpWebRequest request = state as HttpWebRequest;
if (request != null)
request.Abort();
}
}

/// <summary>异步请求获取Html</summary>
/// <param name="getUrl">地址</param>
/// <param name="submitData">提交数据</param>
/// <param name="cookieContainer">cookie容器</param>
/// <param name="header">头类</param>
public void BeginGetHtml(string getUrl, string submitData, CookieContainer cookieContainer, HttpHeader header, Encoding encoding)
{
_Encoding = encoding;
AllDone.Reset();//恢复阻塞状态
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(getUrl);
request.CookieContainer = cookieContainer;
if (header != null)
{
request.ContentType = header.ContentType;
request.ServicePoint.ConnectionLeaseTimeout = header.MaxTry;
request.Accept = header.Accept;
request.UserAgent = header.UserAgent;
request.Method = header.Method;
request.KeepAlive = header.KeepAlive;
request.Referer = header.Referer;
}
request.ProtocolVersion = HttpVersion.Version11;
request.AllowAutoRedirect = true;
request.MaximumAutomaticRedirections = 1;

if (getUrl.ToLower().StartsWith("https"))
{
request.ClientCertificates.Add(_Certificate);
}

//写入提交数据
if (header.Method.ToLower() == "post")
{
request.AllowAutoRedirect = false;
if (!string.IsNullOrWhiteSpace(submitData))
{
byte[] postdatabyte = Encoding.Default.GetBytes(submitData);
request.ContentLength = postdatabyte.Length;
Stream stream;
stream = request.GetRequestStream();
stream.Write(postdatabyte, 0, postdatabyte.Length);
stream.Close();
}
}

RequestState myRequestState = new RequestState();
myRequestState.Request = request;
//开始异步请求
IAsyncResult result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);

ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, _DefaultTimeout, true);

AllDone.WaitOne();//阻断线程,等待执行完成

myRequestState.Response.Close();
}
catch (WebException ex)
{
throw ex;
}
catch (Exception ex)
{
throw ex;
}
}

//异步回调
private void RespCallback(IAsyncResult asynchronousResult)
{
try
{
RequestState myRequestState = (RequestState)asynchronousResult.AsyncState;
HttpWebRequest myHttpWebRequest = myRequestState.Request;
myRequestState.Response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);

Stream responseStream = myRequestState.Response.GetResponseStream();
myRequestState.StreamResponse = responseStream;

IAsyncResult asynchoronosInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, _BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
return;
}
catch (WebException ex)
{
throw ex;
}
//AllDone.Set();
}

//异步分块读取响应Stream的字符串,在此处触发事件,用于提取返回的分块数据
private void ReadCallBack(IAsyncResult asyncResult)
{
try
{
RequestState myRequestState = (RequestState)asyncResult.AsyncState;
Stream responseStream = myRequestState.StreamResponse;
int read = responseStream.EndRead(asyncResult);
//如果有可读数据,读取,递归
if (read > 0)
{
myRequestState.RequestData.Append(_Encoding.GetString(myRequestState.BufferRead, 0, read));
//if (Event_IAsyncReadDataing != null)
//{
// Event_IAsyncReadDataing(myRequestState.RequestData.ToString());
//}
IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, _BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
}
else//没有可读数据(数据读取完成)
{
responseStream.Close();
AllDone.Set();
if (Event_IAsyncReadEnd != null)
{
Event_IAsyncReadEnd(myRequestState.RequestData.ToString());
}
}
}
catch (WebException ex)
{
AllDone.Set(); throw ex;
}
}
}


窗体代码:
HtmlHelper htmlHelper = new HtmlHelper();
public Form1()
{
InitializeComponent();
htmlHelper.Event_IAsyncReadDataing += new Action<string>(htmlHelper_BackCallHtmlString);
htmlHelper.Event_IAsyncReadEnd += new Action<string>(htmlHelper_Event_IAsyncReadEnd);
}

//数据读取结束事件
void htmlHelper_Event_IAsyncReadEnd(string obj)
{
this.Invoke(new Action(() => {
textBox1.Text += obj;
textBox1.Select(textBox1.Text.Length, 0);
textBox1.ScrollToCaret();
}));
}

//按钮单击,循环50次
private void button2_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < 50; i++)
{
htmlHelper.BeginGetHtml("http://120.82.64.9", null, null, new HtmlHelper.HttpHeader() { Method = "post" }, Encoding.Default);
Thread.Sleep(1000);
}
}));
t1.Start();
}

...全文
383 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
xdashewan 2017-04-13
  • 打赏
  • 举报
回复
控制滚动条的代码放到所有线程完成后再进行,不要每次都去滚动
  • 打赏
  • 举报
回复
AllDone 是什么呢?应该把其定义以及相关语句都删除。至于说 Thread.Sleep(1000) 代码,你是业务上需要这样吗?如果不是业务上需要,而是胡乱“技术上”避免某些变量使用混乱(例如使用 AllDone 等变量混乱),那么更应该删掉。因为正是因为这种混乱,你才阻塞你自己、用阻塞和延时来蒙自己,删除掉这些多余的东西之后重新学习设计模式,才能真正解决问题。 有些逻辑一看就知道不是真正的异步设计模式。例如“我先准备Response,然后启动一个子线程来接收数据,启动之后我就阻塞我自己、死等着接受结束再来Response.Close”,这种逻辑就非常荒唐。真正的异步操作是在子线程中接收数据之后就直接 Response.Close,根本不会去死等什么子线程 AllDown.Set。 其实你用一大堆子线程、异步的语法,写了同步顺序的代码。你的许多这类型的代码都是多余的、繁琐的,而且明眼人可以看出这种代码根本没有效率,纯粹是为了一些语法而编程。 删除你的 WaitOne、Set、Sleep,学会真正的异步程序设计模式,不要用繁琐异步操作的语法来模拟别人简单的顺序操作代码(而要真正按照异步、多线程程序设计模式来设计)。再来考虑什么“窗体卡死”的问题。
大刘0417 2017-04-13
  • 打赏
  • 举报
回复
引用 1 楼 sp1234 的回复:
AllDone 是什么呢?应该把其定义以及相关语句都删除。至于说 Thread.Sleep(1000) 代码,你是业务上需要这样吗?如果不是业务上需要,而是胡乱“技术上”避免某些变量使用混乱(例如使用 AllDone 等变量混乱),那么更应该删掉。因为正是因为这种混乱,你才阻塞你自己、用阻塞和延时来蒙自己,删除掉这些多余的东西之后重新学习设计模式,才能真正解决问题。 有些逻辑一看就知道不是真正的异步设计模式。例如“我先准备Response,然后启动一个子线程来接收数据,启动之后我就阻塞我自己、死等着接受结束再来Response.Close”,这种逻辑就非常荒唐。真正的异步操作是在子线程中接收数据之后就直接 Response.Close,根本不会去死等什么子线程 AllDown.Set。 其实你用一大堆子线程、异步的语法,写了同步顺序的代码。你的许多这类型的代码都是多余的、繁琐的,而且明眼人可以看出这种代码根本没有效率,纯粹是为了一些语法而编程。 删除你的 WaitOne、Set、Sleep,学会真正的异步程序设计模式,不要用繁琐异步操作的语法来模拟别人简单的顺序操作代码(而要真正按照异步、多线程程序设计模式来设计)。再来考虑什么“窗体卡死”的问题。
没错,代码中很多都是网上借鉴来的。 您说的,我需要好好研究一下。

110,561

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧