zoukankan      html  css  js  c++  java
  • 用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("
    ", "$").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}
    ", 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等图片都能够成功,当然这些文件要存在代码中所写的目录下面才行

     

  • 相关阅读:
    linux tcp中time_wait
    linux查看系统信息
    运行程序出错无法找到库文件
    安装keepalived
    python 深拷贝与浅拷贝
    python import eventlet包时提示ImportError: cannot import name eventlet
    [原创] 用两个queue实现stack的功能
    [原创] 用两个stack实现queue的功能
    [原创] 编写函数,实现对链表元素的排序与分类
    python 装饰器
  • 原文地址:https://www.cnblogs.com/qigang/p/3918270.html
Copyright © 2011-2022 走看看