用Socket來簡單實現IIS服務器

    剛剛接觸ASP.NET編程,爲了更好的屢清楚服務器的處理過程,就用Socket模擬服務器來處理請求。用Socket來模擬服務器的時候,一樣是本身來封裝一些對應的類文件。包括 HttpRequest、HttpResponse、HttpContext、HttpApplication、IHttpHandel。主要的執行流程是:先用Socket來建立一個簡單的服務器,進行監聽,當監聽到請求後將請求交給處理程序去處理,應用程序中根據請求的是靜態資源仍是動態資源作出不一樣的處理。而後經過Socket對象將響應類容給發送回去。這只是爲了更好的瞭解服務器的處理,進行了一個簡單的模擬,程序中有不少的bug,可是可以實現基本的功能javascript

HttpRequest類

主要包含幾個主要的屬性:請求方式,請求地址,請求協議的版本號css

 1     public class HttpRequest  2  {  3         public HttpRequest (string str)  4  {  5             if (string.IsNullOrEmpty(str))  6  {  7                 return;  8  }  9             string head = str.Replace("\r\n", "$").Split('$')[0]; 10             string[] heads = head.Split(' '); 11             Method = heads.Length>1? heads[0]:""; 12             //獲得請求的絕對路徑
13             Url = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), heads.Length>1? heads[1].Substring(1):heads[0]); 14             Protocol = heads.Length > 1 ? heads[2] : ""; 15 
16  } 17 
18         public string Method { get; set; } 19         public string Url { get; set; } 20         public string Protocol { get; set; } 21     }
HttpRequest類

HttpResponse類

包含響應頭和響應體,在網絡上傳輸的是二進制文件,故將這兩個屬性定義爲byte[],中間還包含其餘的一些屬性。其中響應長度是動態的,在處理程序裏面設置html

 1     public class HttpResponse  2  {  3         public HttpResponse (HttpRequest request)  4  {  5             this.request = request;  6             Type = GetType(Path.GetExtension(request.Url));  7  }  8 
 9         private HttpRequest request; 10         private string Type { get; set; } 11         public int Length { get; set; } 12         public byte[] Head { 13             get
14  { 15 
16                 // -----響應報文------------ 17                 //HTTP/1.1 200 OK 18                 //Connection: keep-alive 19                 //Date: Thu, 26 Jul 2007 14:00:02 GMT 20                 //Server: Microsoft-IIS/6.0 21                 //X-Powered-By: ASP.NET 22                 //Content-Length: 190 23                 //Content-Type: text/html 24                 //Set-Cookie: ASPSESSIONIDSAATTCSQ=JOPPKDCAMHHBEOICJPGPBJOB; path=/ 25                 //Cache-control: private 
26                 ////--空行--
27                 //響應體(正文)
28 
29                 StringBuilder sb = new StringBuilder(); 30                 sb.AppendFormat("{0} {1}\r\n", request.Protocol, "200 OK"); 31                 sb.AppendLine("Date:" + DateTime.Now.ToString()); 32                 sb.AppendLine("Server:QIGANG-PC"); 33                 sb.AppendLine("Content-Length:" + Length); 34                 sb.AppendLine("Content-Type:" + Type); 35  sb.AppendLine(); 36                 return Encoding.UTF8.GetBytes(sb.ToString()); 37 
38 
39  } 40  } 41         public byte[] Body { get; set; } 42 
43     ///根據請求來獲得響應的類型
44         private string GetType (string ext) 45  { 46             string type1 = "text/html;charset=utf-8"; 47             switch (ext)//mime-type
48  { 49                 case ".aspx": 50                 case ".html": 51                 case ".htm": 52                     type1 = "text/html;charset=utf-8"; 53                     break; 54                 case ".png": 55                     type1 = "image/png"; 56                     break; 57                 case ".gif": 58                     type1 = "image/gif"; 59                     break; 60                 case ".jpg": 61                 case ".jpeg": 62                     type1 = "image/jpeg"; 63                     break; 64                 case ".css": 65                     type1 = "text/css"; 66                     break; 67                 case ".js": 68                     type1 = "application/x-javascript"; 69                     break; 70                 default: 71                     type1 = "text/plain;charset=gbk"; 72                     break; 73  } 74             return type1; 75  } 76     }
HttpResponse類

HttpContext類

在這個類裏面簡單的封裝了兩個成員對象,就是HttpRequest和HttpResponse兩個成員,其它的就從簡了java

 1     public class HttpContext  2  {  3         public HttpContext (string str)  4  {  5             Request = new HttpRequest(str);  6             Response = new HttpResponse(Request);  7  }  8         public HttpRequest Request { get; set; }  9         public HttpResponse Response { get; set; } 10     }
HttpContext類

IHttpHandel接口

因爲在客戶端請求的數據中可能請求的是一個動態網頁,這是就須要交給.NET Framework 來進行處理,爲了方便處理,故要求全部的動態網頁都須要實現一個接口,只有實現了這個接口的程序纔可以被瀏覽器給請求到編程

1     public interface IHttpHandel 2  { 3         void ProcessRequest (HttpContext context); 4     }
IHttpHandel接口

服務器端Socket程序

在這主要是啓動一個Socket對象,來進行鏈接的監聽,而後把監聽到的對象交給處理程序 HttpApplication進行處理瀏覽器

 1         private void button1_Click (object sender, EventArgs e)  2  {  3             socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  4             socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 22822));  5             socket.Listen(10);  6             Thread thread = new Thread((obj) =>
 7  {  8                 Socket server = obj as Socket;  9                 while (true) 10  { 11                     Socket client = server.Accept(); 12                     Thread cth = new Thread((obj2) =>
13  { 14                         Socket cSocket = obj2 as Socket; 15 
16                         byte[] by = new byte[cSocket.Available]; 17                         cSocket.Receive(by, 0, by.Length, SocketFlags.None); 18             //拿到請求頭文件
19                         string str = Encoding.UTF8.GetString(by); 20 
21                         /*--------- 調用請求處理函數進行處理 ---------*/
22                         HttpContext context = new HttpContext(str); 23                         HttpApplication app = new HttpApplication(context, cSocket); 24  }); 25                     cth.IsBackground = true; 26  cth.Start(client); 27  } 28  }); 29             thread.IsBackground = true; 30  thread.Start(socket); 31         }
Socket服務端程序

HttpApplication類

這個類須要傳遞一個參數,上下文對象。而後進行請求的解析,根據請求的是靜態資源仍是動態資源去進行不一樣的處理。若是是靜態資源就直接衝磁盤文件中讀取返回,若是是動態資源,就交給對應的類。固然前提是請求的資源名稱就對應了一個類文件。服務器

 1     public class HttpApplication  2  {  3     //構造函數
 4         public HttpApplication (HttpContext context,Socket socket)  5  {  6             string url =context.Request.Url;  7             if(string.IsNullOrEmpty(url)){  8                 return;  9  } 10             string ext = Path.GetExtension(url); 11         //請求的是動態資源文件
12             if (ext == ".aspx") 13  { 14         //下面的代碼中也就沒有進行錯誤的處理了,主要是模擬,沒有考慮其餘的狀況 15         //拿到請求資源的文件名(不包含後綴)
16                 string cs = Path.GetFileNameWithoutExtension(url); 17         //獲得當前程序的程序集
18                 Assembly ass = Assembly.GetExecutingAssembly(); 19         //拿到請求的文件對應的類
20                 Type type = ass.GetType(ass.GetName().Name + "." + cs, true, true); 21         //建立對象,進行調用
22                 IHttpHandel handel = Activator.CreateInstance(type) as IHttpHandel; 23  handel.ProcessRequest(context); 24         //上面幾句話能夠合併到一塊兒,拿到程序集後直接CreateInstance();
25  } 26             else if (ext == ".ashx") 27  { 28  } 29             else//訪問靜態資源
30  { 31                //直接從磁盤中讀取請求的資源文件
32                 byte[] by = File.ReadAllBytes(url); 33                 context.Response.Length = by.Length; 34                 context.Response.Body = by; 35 
36  } 37  socket.Send(context.Response.Head); 38  socket.Send(context.Response.Body); 39  } 40     }
HttpApplication類

整個請求的模型基本上就差很少完成了,若是是請求的動態文件b.aspx,那麼這個b.cs文件須要實現IHttpHandel接口,同時在規定的方法裏面進行處理,代碼以下:網絡

 1 using System;  2 using System.Collections.Generic;  3 using System.IO;  4 using System.Linq;  5 using System.Text;  6 using System.Threading.Tasks;  7 
 8 namespace IIS_Two  9 { 10     public class b:IHttpHandel 11 
12  { 13         public void ProcessRequest (HttpContext context) 14  { 15         //讀取模板HTML文件
16             string html = File.ReadAllText("temp.html"); 17             string temp = "<table border='1'>{0}</table>"; 18         //讀取文本文件類容,拼接一個table表格
19             using (StreamReader reader = new StreamReader("1.txt")) 20  { 21                 string str = ""; 22                 List<string> list = new List<string>(); 23                 while ((str = reader.ReadLine()) != null) 24  { 25                     string[] strs = str.Split(':'); 26                     list.Add("<tr><td>" + strs[0] + "</td><td>" + strs[1] + "</td></tr>"); 27 
28  } 29                 temp = string.Format(temp, string.Join("", list)); 30  } 31         //模板內容的替換
32             html = html.Replace("$body", temp); 33             byte[] by = Encoding.UTF8.GetBytes(html); 34             context.Response.Length = by.Length; 35             context.Response.Body = by; 36  } 37  } 38 }
b.cs文件,對應b.aspx資源

附上b.cs中用到的一個HTML模板和一個txt文件app

 1 <!DOCTYPE html>
 2 
 3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
 4 <head>
 5     <meta charset="utf-8" />
 6     <title></title>
 7 </head>
 8 <body>
 9  $body 10 </body>
11 </html>
temp.html
1 aaa:22 2 bbb:23 3 ccc:18
1.txt

整個簡單的模擬就完成了,bug不少,這不重要。若是請求一個簡單的html頁面或者是jpg等圖片都可以成功,固然這些文件要存在代碼中所寫的目錄下面才行socket

相關文章
相關標籤/搜索