[C#.NET][TCP Socket] 使用 HttpWebRequest 與 HttpWebResponse 類別取得伺服器資訊
Http通訊協定的流程大概是這樣
在.NET裡我們可以使用HttpWebRequest 與 HttpWebResponse 類別來建立 Server 的連線。
使用流程就像下圖,本篇將先介紹GetReponse()的用法,接下來看看實作的過程:
1.建立 HttpWebRequest 物件時無法使用建構函數,必須要使用 WebRquest 抽像類別的 Create() 方法建立。
Uri _uri = new Uri("http://www.dotblogs.com.tw/);
HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(url);
2.建立請求後,可觀察一下所得到的HttepWebRequest資料
const string url = "http://www.dotblogs.com.tw/";
HttpWebRequest _request = null;
HttpWebResponse _response = null;
Uri _uri = null;
private void Form1_Load(object sender, EventArgs e)
{
this._uri = new Uri(url);
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
this._request = (HttpWebRequest)WebRequest.Create(url);
this._request.Method = WebRequestMethods.Http.Get;//預設為GET
this.listBox1.Items.Add("用戶實際回應要求的URI:" + this._request.Address.ToString());
this.listBox1.Items.Add("是否允許重新導向回應:" + this._request.AllowAutoRedirect.ToString());
this.listBox1.Items.Add("是否允許緩衝傳送資料:" + this._request.AllowWriteStreamBuffering.ToString());
this.listBox1.Items.Add("用戶端安全性憑證:" + this._request.ClientCertificates.ToString());
if (this._request.Connection != null)
this.listBox1.Items.Add("與伺服端保持持續性的連結至下達close參數為止:" + this._request.Connection.ToString());
if (this._request.ConnectionGroupName != null)
this.listBox1.Items.Add("連結群組名稱:" + this._request.ConnectionGroupName.ToString());
if (this._request.ContentLength != -1)
this.listBox1.Items.Add("傳送資料內容的大小:" + this._request.ContentLength.ToString());
if (this._request.ContentType != null)
this.listBox1.Items.Add("傳送資料內容的MIME格式:" + this._request.ContentType.ToString());
this.listBox1.Items.Add("是否已接收HTTP伺服端的回應:" + this._request.HaveResponse.ToString());
this.listBox1.Items.Add("是否已接收HTTP在HTTP請求完成之後,是否關閉與HTTP伺服端之連結:" + this._request.KeepAlive.ToString());
this.listBox1.Items.Add("媒體類型:" + this._request.MaximumAutomaticRedirections.ToString());
if (this._request.MediaType != null)
this.listBox1.Items.Add("媒體類型:" + this._request.MediaType.ToString());
this.listBox1.Items.Add("通訊協定方法:" + this._request.Method.ToString());
this.listBox1.Items.Add("是否要求預先驗證:" + this._request.PreAuthenticate.ToString());
this.listBox1.Items.Add("HTTP通訊協定的版本:" + this._request.ProtocolVersion.ToString());
}
3.接下來利用HttpWebRequest.GetResponse方法來取得HttpWebResponse物件
private void button2_Click(object sender, EventArgs e)
{
if (this._request==null)
return;
this.listBox2.Items.Clear();
this._response = (HttpWebResponse)this._request.GetResponse();
HttpStatusCode code = this._response.StatusCode;
int idNumber = (int)code;
this.listBox2.Items.Add("回應的字元編碼格式:" + this._response.CharacterSet.ToString());
this.listBox2.Items.Add("回應的壓縮及編碼格式:" + this._response.CharacterSet.ToString());
this.listBox2.Items.Add("回應資料內容的大小:" + this._response.ContentLength.ToString());
this.listBox2.Items.Add("回應資料內容的MIME格式:" + this._response.ContentType.ToString());
this.listBox2.Items.Add("最近修改回應內容的日期時間:" + this._response.LastModified.ToString());
this.listBox2.Items.Add("回應通訊協定的版本:" + this._response.ProtocolVersion.ToString());
this.listBox2.Items.Add("伺服端所回應的URI:" + this._response.ResponseUri.ToString());
this.listBox2.Items.Add("傳送回應的伺服器名稱:" + this._response.Server.ToString());
this.listBox2.Items.Add("回應訊息狀態的編碼編號:" + idNumber.ToString());
this.listBox2.Items.Add("回應訊息狀態的編碼狀態:" + this._response.StatusCode.ToString());
this.listBox2.Items.Add("回應訊息狀態的描述:" + this._response.StatusDescription.ToString());
this._response.Close();
}
特別提一下上段程式碼有使用到 HttpStatusCode 列舉型別,這是伺服器回應後所拋出的訊息,用來告訴使用者回應的狀況是否正確。
GetResponse非同步方法是 BeginGetResponse 跟 EndGetResponse;BeginGetResponse是開始非同步作業,EndGetResponse則是取得非同步資料。
HttpWebRequest request = Result.AsyncState as HttpWebRequest;
HttpWebResponse response = request.EndGetResponse(Result) as HttpWebResponse;//取得資料
完整範例如下:
private void button3_Click(object sender, EventArgs e)
{
if (this._request == null)
return;
this.listBox2.Items.Clear();
RequestState state = new RequestState();
IAsyncResult result = (IAsyncResult)this._request.BeginGetResponse(new AsyncCallback(Callback), this._request);
}
void Callback(IAsyncResult Result)
{
HttpWebRequest request = Result.AsyncState as HttpWebRequest;
HttpWebResponse response = request.EndGetResponse(Result) as HttpWebResponse;//取得資料
HttpStatusCode code = response.StatusCode;
int id = (int)code;
//跨執行緒更新
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應的字元編碼格式:" + response.CharacterSet.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應的壓縮及編碼格式:" + response.CharacterSet.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應資料內容的大小:" + response.ContentLength.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應資料內容的MIME格式:" + response.ContentType.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "最近修改回應內容的日期時間:" + response.LastModified.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應通訊協定的版本:" + response.ProtocolVersion.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "伺服端所回應的URI:" + response.ResponseUri.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "傳送回應的伺服器名稱:" + response.Server.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應訊息狀態的編碼編號:" + id.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應訊息狀態的編碼狀態:" + response.StatusCode.ToString() });
this.BeginInvoke(new delegateUpdateControl(UpdateControl), new object[] { listBox2, "回應訊息狀態的描述:" + response.StatusDescription.ToString() });
response.Close();
}
執行結果就跟上面 button2_Click 一樣。
這個非同步方法,經我使用測試的結果,好像還是會造成主執行緒畫面卡住,真奇怪,再用一層執行緒包起來就能夠解決。
private void button4_Click(object sender, EventArgs e)
{
if (this._request == null)
return;
this.listBox2.Items.Clear();
ThreadPool.QueueUserWorkItem(new WaitCallback(PoolDoWorker));
}
void PoolDoWorker(object i)
{
Thread t = Thread.CurrentThread;
Console.WriteLine("No.{0}-Thread[{1}]:{2}", i, t.ManagedThreadId, t.ThreadState);
IAsyncResult result = (IAsyncResult)this._request.BeginGetResponse(new AsyncCallback(Callback), this._request);
}
在研究非同步方法時,花了很多的時間在測試畫面卡住的問題,本以為是哪個方法沒用好,最後還是選擇心中一開始就想到的路,才解決掉畫面卡住的問題,研究的過程真的很有趣,為了解決問題會看更多的資料。
使用GetResponse的例外狀況
使用GetResponseStream的例外狀況
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET