[C#.NET][TCP Socket] 使用 HttpWebRequest 與 HttpWebResponse 類別取得伺服器資訊

  • 9272
  • 0
  • 2013-08-16

[C#.NET][TCP Socket] 使用 HttpWebRequest 與 HttpWebResponse 類別取得伺服器資訊

Http通訊協定的流程大概是這樣

image

 

 

在.NET裡我們可以使用HttpWebRequestHttpWebResponse 類別來建立 Server 的連線。

使用流程就像下圖,本篇將先介紹GetReponse()的用法,接下來看看實作的過程:

image


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());
}

 

image

 

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();
}

 

image

 

特別提一下上段程式碼有使用到 HttpStatusCode 列舉型別,這是伺服器回應後所拋出的訊息,用來告訴使用者回應的狀況是否正確。

 


GetResponse非同步方法是 BeginGetResponseEndGetResponse;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);
}


後記:HttpWebResRep.zip

在研究非同步方法時,花了很多的時間在測試畫面卡住的問題,本以為是哪個方法沒用好,最後還是選擇心中一開始就想到的路,才解決掉畫面卡住的問題,研究的過程真的很有趣,為了解決問題會看更多的資料。

使用GetResponse的例外狀況

image

使用GetResponseStream的例外狀況

image

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo