對IIS只有表面的理解 現在模擬一下IIS的內部原理:

1 public int ServerScoket { get; set; } 2 private void btnStart_Click(object sender, EventArgs e) 3 { 4 IPAddress ipAddress = IPAddress.Parse(this.txtIP.Text); 5 IPEndPoint endpoint = new IPEndPoint(ipAddress, int.Parse(this.txtPort.Text)); 6 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 7 socket.Bind(endpoint); 8 socket.Listen(10); 9 this.lbStatus.Text = "啟動"; 10 this.lbStatus.ForeColor = Color.Green; 11 //開始socket的接受請求 12 ThreadPool.QueueUserWorkItem(a => 13 { 14 //線程池默認都是后台線程 15 Socket serverSocket = (Socket)a; 16 while (true) 17 { 18 //獲取到跟瀏覽器交互的代理socket 19 var proxSocket= serverSocket.Accept(); 20 21 ThreadPool.QueueUserWorkItem(s => 22 { 23 Socket pSocket = (Socket)s; 24 byte[] bytes = new byte[1024 * 1024]; 25 int realLength = pSocket.Receive(bytes); 26 //把當前的報文封裝到了strRequest里面去了 27 string strRequest = Encoding.UTF8.GetString(bytes, 0, realLength); 28 //處理當前的報文,解析當前報文,看看請求是哪個文件, 29 //把請求的文件封裝成相應的報文,通過socket發送給瀏覽器 30 ProcessRequest(strRequest, pSocket); 31 }, proxSocket); 32 } 33 },socket); 34 } 35 //處理客戶端的請求 36 private void ProcessRequest(string strRequest, Socket pSocket) 37 { 38 //把請求行取出來 39 //初始化請求信息和響應信息實例 40 HttpContext context = new HttpContext(strRequest); 41 HttpApplication application = new HttpApplication(); 42 43 //這時候,請求的響應已經做好了 44 //正在處理HTTP請求 45 application.ProcessRequest(context); 46 47 //context response 48 pSocket.Send(context.Response.GetHeader()); 49 pSocket.Send(context.Response.BodyData); 50 pSocket.Shutdown(SocketShutdown.Both); 51 pSocket.Close(); 52 }
HttpContext封裝上下文
public class HttpContext { //設置請求 public HttpRequest Request { get; set; } //響應的實例 public HttpResponse Response { get; set; } //構造函數 public HttpContext(string httpRequestStr) { Request = new HttpRequest(httpRequestStr); Response = new HttpResponse(Request); } }
HttpRequest對象:
1 /// <summary> 2 /// 封裝請求報文的信息 3 /// </summary> 4 public class HttpRequest 5 { 6 /* 7 GET /login.aspx HTTP/1.1 8 Accept: text/html, application/xhtml+xml, #1#* 9 Accept-Language: zh-CN 10 User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; QDesk 2.3.1185.202; Windows NT 6.1; Trident/5.0) 11 Accept-Encoding: gzip, deflate 12 Host: localhost:38888 13 Connection: Keep-Alive*/ 14 15 //將報文傳進來 16 public HttpRequest(string requestStr) 17 { 18 if(!string.IsNullOrEmpty(requestStr)) 19 { 20 string[] lines=requestStr.Replace("\r\n","\r").Split('\r'); 21 //處理請求的Method 22 this.Method = lines[0].Split(' ')[0]; 23 //設置請求的URL 地址 24 this.RequestURL = lines[0].Split(' ')[1]; 25 } 26 } 27 //是Get 還是set 28 public string Method { get; set; } 29 public string RequestURL { get; set; } 30 }
HttpResponse

1 public class HttpResponse 2 { 3 //請求文件的后綴 4 private string _requestFileExt; 5 public HttpResponse(HttpRequest request) 6 { 7 _requestFileExt = Path.GetExtension(request.RequestURL); 8 } 9 //獲取相應提報文字節數組 10 public byte[] BodyData { get; set; } 11 //獲取響應頭部 12 public byte[] GetHeader() 13 { 14 StringBuilder sb = new StringBuilder(); 15 sb.AppendFormat("HTTP/1.1 200 OK\r\n"); 16 sb.AppendFormat("Content-Type: {0} \r\n", GetContentType(_requestFileExt)); 17 return Encoding.UTF8.GetBytes(sb.ToString()); 18 } 19 20 public string GetContentType(string _requestFileExt) 21 { 22 string type = "text/html"; 23 switch (_requestFileExt) 24 { 25 case ".aspx": 26 case ".html": 27 case ".htm": 28 type = "text/html"; 29 break; 30 case ".png": 31 type = "image/png"; 32 break; 33 case ".gif": 34 type = "image/gif"; 35 break; 36 case ".jpg": 37 case ".jpeg": 38 type = "image/jpeg"; 39 break; 40 case ".css": 41 type = "text/css"; 42 break; 43 case ".js": 44 type = "application/x-javascript"; 45 break; 46 default: 47 type = "text/plain"; 48 break; 49 } 50 return type; 51 } 52 53 //返回響應主體 54 public byte[] GetBodyData() 55 { 56 return BodyData; 57 } 58 }
HttpApplication 中處理
1 public class HttpApplication 2 { public void ProcessRequest(HttpContext context) 3 { 4 string ext = Path.GetExtension(context.Request.RequestURL); 5 switch (ext) 6 { 7 case ".jpg": 8 case ".jpeg": 9 case ".html": 10 case ".htm": 11 case ".css": 12 case ".js": 13 ProcessStaticFile(context); break; 14 case ".aspx": 15 ProcessDynamicFile(context); 16 break; 17 default: 18 ProcessStaticFile(context); 19 break; 20 } 21 } 22 //處理動態頁面 23 public void ProcessDynamicFile(HttpContext context) 24 { 25 //假設請求Index.aspx 26 string className=Path.GetFileNameWithoutExtension(context.Request.RequestURL); 27 //獲取命名空間 28 string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace; 29 //_02HeimaIIS.IndexPage 30 string fullName = nameSpace + "." + className; 31 //用接口接受不同的實例 32 IHttpHandler obj=(IHttpHandler)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName,true); 33 if (obj == null) 34 { 35 36 } 37 else 38 { 39 obj.ProcessRequest(context); 40 } 41 } 42 //處理靜態頁面 43 public void ProcessStaticFile(HttpContext context) 44 { 45 string currentWebDir = AppDomain.CurrentDomain.BaseDirectory; 46 string fileName=Path.Combine(currentWebDir,context.Request.RequestURL.TrimStart('/')); 47 context.Response.BodyData = File.ReadAllBytes(fileName); 48 } 49 }
如果是靜態網頁直接返回
如果是動態頁面通過反射實現
以上就是面向接口編程
1 public class MyPage : IHttpHandler 2 { 3 public void ProcessRequest(HttpContext context) 4 { 5 //可以訪問數據庫,就是動態的 6 string strBody = @"<html><head></head><body><h2> big shit y</h2></body></html>"; 7 context.Response.BodyData = Encoding.UTF8.GetBytes(strBody); 8 } 9 }
IIS內部處理的文字總結:
設置一個監聽隊列,用一個應用程序池中的實例socket A,接受瀏覽器發送的數據,再從應用程序池中獲取一個實例 socket B將接受到的數據進行處理,而 socket A 不斷接受瀏覽器的請求。
socket B處理數據(用到HttpContext HttpApplication MyPage IHandler)
HttpContext
HttpRequest 獲取請求的方法 及請求的地址
HttpResponse得到響應體和 響應頭
HttpApplication
根據后綴名判斷是動態網頁還是靜態網頁
動態網頁:通過反射獲取命名空間 通過請求地址找到類名 通過反射獲取實例轉化成接口,調用其方法。
處理完成后,由代理socket發送報文頭和報文體