用Socket来简单实现IIS服务器


    刚刚接触ASP.NET编程,为了更好的屡清楚服务器的处理过程,就用Socket模拟服务器来处理请求。用Socket来模拟服务器的时候,同样是自己来封装一些对应的类文件。包括 HttpRequest、HttpResponse、HttpContext、HttpApplication、IHttpHandel。主要的执行流程是:先用Socket来创建一个简单的服务器,进行监听,当监听到请求后将请求交给处理程序去处理,应用程序中根据请求的是静态资源还是动态资源做出不同的处理。然后通过Socket对象将响应类容给发送回去。这只是为了更好的了解服务器的处理,进行了一个简单的模拟,程序中有很多的bug,但是能够实现基本的功能

HttpRequest类

主要包含几个主要的属性:请求方式,请求地址,请求协议的版本号

 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[],中间还包含其他的一些属性。其中响应长度是动态的,在处理程序里面设置

 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两个成员,其它的就从简了

 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文件

 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等图片都能够成功,当然这些文件要存在代码中所写的目录下面才行

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM