HTTP協議--MyWebServer

HTTP協議

HTTP協議是一種Web通訊協議,經過特定的規則來實現服務器跟客戶端的通訊。HTTP協議有這樣幾個特色:javascript

(1)面向無鏈接的,一次只能處理一個請求,HTTP1.0服務器解析完客戶端請求並做出應答後,會關閉鏈接;對於HTTP1.1應答後會等待一個很是短的時間,若是這段時間沒有新請求,就會關閉鏈接。css

(2)HTTP協議是無狀態的,即對處理過的事務沒有記憶能力,它認爲每一次請求都是陌生的獨立的,爲了解決這個問題,Web服務程序引進了cookie機制來維持請求狀態。html

(3)HTTP協議容許傳輸任意類型的數據,對於正在傳輸的數據類型用Content-Type標記。java

URL

url須要提供幾種信息,一是採用的協議,二是鏈接的套接字,三是請求文件的路徑,後面還能夠跟上請求參數web

在瀏覽器中輸入www.csdn.net,瀏覽器會自動幫咱們轉化爲http://www.csdn.net/。數組

採用的協議,這裏已HTTP爲例;鏈接套接字包括ip地址跟端口號,端口號通常都是默認的,不須要咱們輸入,ip地址咱們通常輸入域名,而後經過域名服務器解析;請求的路徑,通常web程序會提供一個默認路徑,若是不輸,就是默認的;路徑後面還能夠跟上GET請求的參數,在請求路徑後加上"?"參數之間用「&」鏈接。通常來講簡單的無安全要求的數據,咱們直接經過GET方法傳遞給服務器,而大量的隱私的數據咱們經過Post方法傳遞給服務器。瀏覽器

HTTP請求報文

請求報文分爲三個部分,請求行、請求頭、請求體,格式都是固定的。如圖1.1所示:安全

請求的方法以下:服務器

(1)GET   請求獲取url標識的資源cookie

(2)POST  請求獲取url標識的資源並像瀏覽器傳遞數據

(3)HEAD  請求服務器對url的響應報頭

(4)PUT  請求服務器存儲資源,並以url做爲其標識

(5)DELETE 請求服務器刪除url標識的資源

(6)TRACE  請求服務器返回發送過去的請求,主要用於診斷和測試

HTTP響應報文

響應報文也分爲三個部分,響應行、響應頭、響應體,如圖1.2所示:

響應行包含了協議版本,狀態碼,和狀態碼的描述。

狀態碼是一個百位數,100段表示請求已接受,繼續處理;200段表示請求成功;300段表示請求須要作進一步處理,好比說跳轉;400段表示請求錯誤,而且是客戶端的緣由;500段表示服務器的緣由致使了請求錯誤。

常見的響應碼以下:

200 : OK

302 : Found 重定向

400 : Bad Request 錯誤請求,發出錯誤的不符合Http協議的請求

401 : Unauthorized  請求未經受權,這個狀態代碼必須和WWW-Authenticate報頭域一塊兒使用

403 : Forbidden 禁止

404 : Not Found 未找到

500 : Internal Server Error 服務器內部錯誤

503 : Service Unavailable  通常是訪問人數過多

經常使用的類型名:

Server 提供web服務器版本信息;Content-Type 響應的內容的類型 ;Content-Length 響應體的字節長度  ;Connetion 鏈接的方式信息 ;Accept-Ranges 接收數據的方式,一般是字節數組。

 

MyWebServer

複習,模擬一個本身的簡單服務器程序,步驟以下:

一、接收瀏覽器發送的請求(socket)
二、分析請求報文(http),請求的路徑
三、生成響應報文,響應體
四、發送響應內容

//用的winform,首先搭建一個窗體,點擊開始後開始監聽。

 

[csharp]  view plain  copy
 
  1. namespace MyWebServer  
  2. {  
  3.     public partial class Form1 : Form  
  4.     {  
  5.         public Form1()  
  6.         {  
  7.             InitializeComponent();  
  8.             Control.CheckForIllegalCrossThreadCalls = false;  
  9.         }  
  10.         void ShowMsg(string str)  
  11.         {  
  12.             txtLog.AppendText(str+"\r\n");  
  13.         }  
  14.         private void btnStart_Click(object sender, EventArgs e)  
  15.         {  
  16.             //點擊開始運行,建立一個socket對象並進行監聽  
  17.             IPAddress ip;int p;  
  18.             if (!IPAddress.TryParse(txtIp.Text, out ip))  
  19.             {  
  20.                 MessageBox.Show("請輸入一個正確的ip地址");  
  21.                 return;  
  22.             }  
  23.             if(!int.TryParse(txtPort.Text,out p))  
  24.             {  
  25.                 MessageBox.Show("請輸入一個正確的端口號");  
  26.                 return ;  
  27.             }  
  28.             IPEndPoint point = new IPEndPoint(ip, p);  
  29.             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
  30.             try  
  31.             {  
  32.                 socket.Bind(point);//綁定地址  
  33.                 socket.Listen(10);//開始監聽  
  34.                 ShowMsg("開始運行。。。");  
  35.                 //建立一個後臺線程接受客戶端的鏈接  
  36.                 Thread th = new Thread(Listen);  
  37.                 th.IsBackground = true;  
  38.                 th.Start(socket);  
  39.             }  
  40.             catch (Exception ex)  
  41.             {  
  42.                 MessageBox.Show(ex.Message);  
  43.             }  
  44.         }  
  45.         private void Listen(object o)  
  46.         {  
  47.             Socket socket = o as Socket;  
  48.             while (true)  
  49.             {  
  50.                 Socket connSocket = socket.Accept();//通訊用的socket  
  51.                 ShowMsg(connSocket.RemoteEndPoint + "鏈接成功");  
  52.                 //建立一個DataConnection類專門接收請求和發送響應  
  53.                 DataConnection dc = new DataConnection(connSocket, ShowMsg);  
  54.                   
  55.             }  
  56.         }  
  57.     }  
  58. }  

其中接收和發送請求交給DataConnection

 

 

[csharp]  view plain  copy
 
  1. namespace MyWebServer  
  2. {  
  3.     delegate void DelHandler(string str);//用於傳遞方法ShowMsg  
  4.     class DataConnection  
  5.     {  
  6.         Socket connsocket; DelHandler del; string request;  
  7.         public DataConnection(Socket socket,DelHandler del)  
  8.         {  
  9.             connsocket=socket;  
  10.             this.del = del;  
  11.             request = RecRequest();  
  12.             del(request);//經過委託調用窗體的ShowMsg方法,顯示請求報文  
  13.             //分析請求報文,放在Request類中進行  
  14.             Request req = new Request(request);  
  15.             staticPage(req.Url);  
  16.         }  
  17.         //處理靜態頁面,根據請求的路徑來判斷  
  18.         void staticPage(string url)  
  19.         {  
  20.             string extension = Path.GetExtension(url).TrimStart('.');//獲取後綴名  
  21.             switch (extension)  
  22.             {  
  23.                 case "html":  
  24.                 case "htm":  
  25.                 case "css":  
  26.                 case "js":  
  27.                 case "jpg":  
  28.                 case "png":  
  29.                 case "gif":  
  30.                     //處理靜態頁面,生產響應有Response類負責  
  31.                     ProcessStaticPage(url);  
  32.                     break;  
  33.                 case"she":  
  34.                     //處理動態頁面  
  35.   
  36.                     break;  
  37.                 default:  
  38.                     break;  
  39.             }  
  40.         }  
  41.         //處理靜態頁面  
  42.         void ProcessStaticPage(string url)  
  43.         {   
  44.             //求出絕對路徑  
  45.             string path = AppDomain.CurrentDomain.BaseDirectory + url;  
  46.             //判斷文件是否存在  
  47.             if (File.Exists(path))  
  48.             {  
  49.                 using (FileStream fs=new FileStream(path,FileMode.Open))  
  50.                 {  
  51.                     //讀取文件  
  52.                     byte[]buffer=new byte[fs.Length];  
  53.                     fs.Read(buffer, 0, buffer.Length);  
  54.                     //生成響應頭,交給Response類  
  55.                     Response response = new Response(200, buffer.Length, url);  
  56.                     connsocket.Send(response.GetResponseHeads());  
  57.                     connsocket.Send(buffer);  
  58.   
  59.                     connsocket.Close();  
  60.                     del("關閉了鏈接");  
  61.                 }  
  62.             }  
  63.             else  
  64.             {  
  65.                 //文件不存在,404頁面  
  66.                             }  
  67.         }  
  68.         void ProcessDTPage(string url)  
  69.         {  
  70.             string fileName = Path.GetFileNameWithoutExtension(url);//通常把文件名定義成類名  
  71.             //獲取當前方法所在的命名空間  
  72.             string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;  
  73.             //類的全名稱  
  74.             string fullName = nameSpace + "." + fileName;  
  75.             IHttpHandler handler = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;  
  76.             if (handler != null)  
  77.             {  
  78.                 //響應體  
  79.                 byte[] buffer = handler.ProcessRequest();  
  80.                 //響應頭  
  81.                 Response res = new Response(200, buffer.Length, url);  
  82.   
  83.                 //發送  
  84.                 connsocket.Send(res.GetResponseHeads());  
  85.                 connsocket.Send(buffer);  
  86.                 connsocket.Close();  
  87.                 del("關閉鏈接");  
  88.             }  
  89.         }  
  90.         //接收請求報文  
  91.         string RecRequest()  
  92.         {  
  93.             byte[] buffer = new byte[1024 * 1024];  
  94.             int num=connsocket.Receive(buffer);  
  95.             return Encoding.UTF8.GetString(buffer,0,num);  
  96.   
  97.         }  
  98.   
  99.     }  
  100. }  

分割請求信息獲得路徑和準備響應頭都交給對應的類作了:

 

 

[csharp]  view plain  copy
 
  1. class Request  
  2. {  
  3.     string request; public string Url;  
  4.     public Request(string request)  
  5.     {  
  6.   
  7.         try  
  8.         {  
  9.             string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);  
  10.             string first = strs[0];  
  11.             string[] requstHeads = first.Split( ' ');  
  12.             Url = requstHeads[1];//請求行中的路徑  
  13.         }  
  14.         catch (Exception ex)  
  15.         {  
  16.             Url = "";  
  17.         }  
  18.     }  
  19. }  
[csharp]  view plain  copy
 
  1. class Response  
  2. {  
  3.     Dictionary<int, string> dic = new Dictionary<int, string>();//存狀態碼根描述  
  4.     int stateCode = 200;  
  5.     int contentLength;  
  6.     string contentType;  
  7.     public Response(int stateCode,int contentLength,string url)  
  8.     {  
  9.         Fill();  
  10.         this.stateCode = stateCode;  
  11.         this.contentLength = contentLength;  
  12.         GetContentType(url);  
  13.     }  
  14.     //生成響應頭  
  15.     public byte[] GetResponseHeads()  
  16.     {  
  17.         StringBuilder sb = new StringBuilder();  
  18.         sb.AppendLine("HTTP/1.1 "+stateCode+" "+dic[stateCode]);  
  19.         sb.AppendLine("Content-Length: " + contentLength);  
  20.         sb.AppendLine("Content-Type: "+ contentType +";charset=utf-8\r\n");  
  21.         return Encoding.UTF8.GetBytes(sb.ToString());  
  22.     }  
  23.     //根據後綴給contenttype賦值  
  24.     void GetContentType(string url)  
  25.     {  
  26.         //.htm  
  27.         string ext = Path.GetExtension(url);  
  28.         switch (ext)  
  29.         {  
  30.             case ".htm":  
  31.             case ".html":  
  32.                 contentType = "text/html";  
  33.                 break;  
  34.             case ".css":  
  35.                 contentType = "text/css";  
  36.                 break;  
  37.             case ".js":  
  38.                 contentType = "text/javascript";  
  39.                 break;  
  40.             case ".jpg":  
  41.                 contentType = "image/jpeg";  
  42.                 break;  
  43.             default:  
  44.                 contentType = "text/html";  
  45.                 break;  
  46.         }  
  47.     }  
  48.     void Fill()  
  49.     {  
  50.         dic.Add(200, "OK");  
  51.         dic.Add(400, "Not Found");  
  52.     }  
  53. }  
相關文章
相關標籤/搜索