http://www.sufeinet.com/plugin.php?id=keke_group

苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 4953|回复: 3

[IIS] C#IIS的内部原理实现

[复制链接]
发表于 2012-9-28 16:16:58 | 显示全部楼层 |阅读模式
对IIS只有表面的理解   现在模拟一下IIS的内部原理:
[C#] 纯文本查看 复制代码
         public int ServerScoket { get; set; }
         private void btnStart_Click(object sender, EventArgs e)
         {
             IPAddress ipAddress = IPAddress.Parse(this.txtIP.Text);
             IPEndPoint endpoint = new IPEndPoint(ipAddress, int.Parse(this.txtPort.Text));
             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             socket.Bind(endpoint);
             socket.Listen(10);
             this.lbStatus.Text = "启动";
             this.lbStatus.ForeColor = Color.Green;
             //开始socket的接受请求
             ThreadPool.QueueUserWorkItem(a =>
                 {
                     //线程池默认都是后台线程
                     Socket serverSocket = (Socket)a;
                     while (true)
                     {
                         //获取到跟浏览器交互的代理socket
                        var proxSocket= serverSocket.Accept();
                         
                        ThreadPool.QueueUserWorkItem(s => 
                        {
                            Socket pSocket = (Socket)s;
                            byte[] bytes = new byte[1024 * 1024];
                            int realLength = pSocket.Receive(bytes);
                            //把当前的报文封装到了strRequest里面去了
                            string strRequest = Encoding.UTF8.GetString(bytes, 0, realLength);
                            //处理当前的报文,解析当前报文,看看请求是哪个文件,
                            //把请求的文件封装成相应的报文,通过socket发送给浏览器
                            ProcessRequest(strRequest, pSocket);
                        }, proxSocket);
                     }
                 },socket);
         }
         //处理客户端的请求
         private void ProcessRequest(string strRequest, Socket pSocket)
         {
             //把请求行取出来
             //初始化请求信息和响应信息实例
             HttpContext context = new HttpContext(strRequest);
             HttpApplication application = new HttpApplication();
 
             //这时候,请求的响应已经做好了
             //正在处理HTTP请求
             application.ProcessRequest(context);
 
             //context response
             pSocket.Send(context.Response.GetHeader());
             pSocket.Send(context.Response.BodyData);
             pSocket.Shutdown(SocketShutdown.Both);
             pSocket.Close();
         }

HttpContext封装上下文
[C#] 纯文本查看 复制代码
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对象
[C#] 纯文本查看 复制代码
/// <summary>
     /// 封装请求报文的信息
     /// </summary>
   public  class HttpRequest
     {
         /*
          GET /login.aspx HTTP/1.1
         Accept: text/html, application/xhtml+xml, #1#*
         Accept-Language: zh-CN
         User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; QDesk 2.3.1185.202; Windows NT 6.1; Trident/5.0)
         Accept-Encoding: gzip, deflate
         Host: localhost:38888
         Connection: Keep-Alive*/
 
       //将报文传进来
       public HttpRequest(string requestStr)
       {
           if(!string.IsNullOrEmpty(requestStr))
           {
             string[] lines=requestStr.Replace("\r\n","\r").Split('\r');
               //处理请求的Method
             this.Method = lines[0].Split(' ')[0];
               //设置请求的URL 地址
             this.RequestURL = lines[0].Split(' ')[1];
           }
       }
       //是Get 还是set
       public string  Method { get; set; }
       public string  RequestURL { get; set; }
     }

HttpResponse
[C#] 纯文本查看 复制代码
View Code 
   public class HttpResponse
     {
        //请求文件的后缀
        private string _requestFileExt;
        public HttpResponse(HttpRequest request)
        {
            _requestFileExt = Path.GetExtension(request.RequestURL);
        }
        //获取相应提报文字节数组
        public byte[] BodyData { get; set; }
        //获取响应头部
        public byte[] GetHeader()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("HTTP/1.1 200 OK\r\n");
            sb.AppendFormat("Content-Type: {0} \r\n", GetContentType(_requestFileExt));
            return Encoding.UTF8.GetBytes(sb.ToString());
        }
 
        public string GetContentType(string _requestFileExt)
        {
            string type = "text/html";
            switch (_requestFileExt)
            {
                case ".aspx":
                    case ".html":
                 case ".htm":
                     type = "text/html";
                     break;
                 case ".png":
                     type = "image/png";
                     break;
                 case ".gif":
                     type = "image/gif";
                     break;
                 case ".jpg":
                 case ".jpeg":
                     type = "image/jpeg";
                     break;
                 case ".css":
                     type = "text/css";
                     break;
                 case ".js":
                     type = "application/x-javascript";
                     break;
                 default:
                     type = "text/plain";
                     break;
            }
            return type;
        }
 
        //返回响应主体
        public byte[] GetBodyData()
        {
            return BodyData;
        }
     }

HttpApplication 中处理
[C#] 纯文本查看 复制代码
public  class HttpApplication
     { public void ProcessRequest(HttpContext context)
        {
            string ext = Path.GetExtension(context.Request.RequestURL);
            switch (ext)
            {
                case ".jpg":
                case ".jpeg":
                case ".html":
                case ".htm":
                case ".css":
                case ".js":
                    ProcessStaticFile(context); break;
                case ".aspx":
                    ProcessDynamicFile(context);
                    break;
                default:
                    ProcessStaticFile(context);
                    break;
            }
        }
        //处理动态页面
        public void ProcessDynamicFile(HttpContext context)
        {
            //假设请求Index.aspx
            string className=Path.GetFileNameWithoutExtension(context.Request.RequestURL);
            //获取命名空间
            string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
            //_02HeimaIIS.IndexPage
            string fullName = nameSpace + "." + className;
            //用接口接受不同的实例
            IHttpHandler obj=(IHttpHandler)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName,true);
            if (obj == null)
            {
 
            }
            else
            {
                obj.ProcessRequest(context);
            }
        }
        //处理静态页面
        public void ProcessStaticFile(HttpContext context)
        {
            string currentWebDir = AppDomain.CurrentDomain.BaseDirectory;
            string fileName=Path.Combine(currentWebDir,context.Request.RequestURL.TrimStart('/'));
            context.Response.BodyData = File.ReadAllBytes(fileName);
        }
     }

如果是静态网页直接返回
如果是动态页面通过反射实现
以上就是面向接口编程
[C#] 纯文本查看 复制代码
public class MyPage : IHttpHandler
     {
         public void ProcessRequest(HttpContext context)
         {
             //可以访问数据库,就是动态的
             string strBody = @"<html><head></head><body><h2> big shit y</h2></body></html>";
             context.Response.BodyData = Encoding.UTF8.GetBytes(strBody);
         }      
     }

IIS内部处理的文字总结:
设置一个监听队列,用一个应用程序池中的实例socket A,接受浏览器发送的数据,再从应用程序池中获取一个实例 socket B将接受到的数据进行处理,而 socket A 不断接受浏览器的请求。
socket B处理数据(用到HttpContext HttpApplication MyPage IHandler)
HttpContext
  HttpRequest 获取请求的方法 及请求的地址
  HttpResponse得到响应体和 响应头
HttpApplication
  根据后缀名判断是动态网页还是静态网页
  动态网页:通过反射获取命名空间  通过请求地址找到类名  通过反射获取实例转化成接口,调用其方法。
处理完成后,由代理socket发送报文头和报文体


1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
发表于 2013-7-6 11:08:38 | 显示全部楼层
真是难得给力的帖子啊,强烈支持楼主。
发表于 2013-8-1 23:38:42 | 显示全部楼层
受教了,学习中……
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-4-29 03:46

© 2014-2021

快速回复 返回顶部 返回列表