C#模拟IIS服务器(一)


为了更加透彻理解 IIS 服务器原理,自己简单模拟了IIS服务器工作原理,事实证明确实有助于理解!

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace 小型IIS服务器
{
    using System.Net.Sockets;
    using System.Net;


    /// <summary>
    /// 负责网站socket的监听
    /// </summary>
    public class IISWebServer
    {
        #region 1.0 定义变量
        //定义服务器端监听socket
        Socket serverSocket;
        //服务器IP地址
        string ip;
        //服务器端口号
        int port;
        //定义action泛型委托 传递一个方法进来 为txtRequestStr赋值 将客户端请求报文 显示出来
        Action<string> displayMsg;
        //是否继续循环 用于监听和响应
        bool isStop = false;


        #endregion


        #region 2.0 构造函数实例化 ip port 传进方法 给txtRequestStr赋值
        /// <summary>
        /// 无参构造方法
        /// </summary>
        public IISWebServer() { }


        /// <summary>
        /// 有参构造方法
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="displayMsg"></param>
        public IISWebServer(string ip, int port, Action<string> displayMsg)
        {
            this.ip = ip;
            this.port = port;
            this.displayMsg = displayMsg;
        }
        #endregion


        #region 3.0 启动IIS服务器的方法 入口 在Form1 btnStart_Click 方法中被调用


        /// <summary>
        /// 启动IIS服务器
        /// </summary>
        public void Start()
        {
            //01 实例化一个流式套接口
            //使用IP4 IP地址 Stream流式套接口 TCP协议
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


            //02 给套接口绑定ip port
            //IPEndPoint 将网络端点表示为 ip地址 和 端口号
            //IPAddress 提供网际协议(IP)地址
            //IPAddress.Parse(string ip) 让IP地址字符串转换为system.Net.IPAddress实例
            //IPEndPoint(IPAddress.Parse(ip),port) 用指定的IP port 初始化system.Net.IPEndPoint的新实例
            IPEndPoint ipp = new IPEndPoint(IPAddress.Parse(ip), port);
            serverSocket.Bind(ipp);


            //03 打开监听
            serverSocket.Listen(20);


            //04 开启线程等待浏览器的请求 由于AcceptCilent()会阻断主线程 所以开启子线程来接收客户端链接
            System.Threading.Thread th = new System.Threading.Thread(AcceptCilent);
            th.IsBackground = true;     //该线程是否为后台线程
            th.Start();
        }


        #endregion


        #region 4.0 等待浏览器向服务器请求
        /// <summary>
        /// 等待浏览器向服务器请求
        /// </summary>
        private void AcceptCilent()
        {
            while (!isStop)
            {
                try
                {
                    //开启服务器之后 代码执行到这就会停止 等待用户连接 一旦连接 就继续往下执行
                    //01 浏览器已发出请求 就会触发Accept()方法
                    Socket cSocket = serverSocket.Accept();


                    //02 监听到浏览器发出请求后 定义一个子线程 用来接收请求报文 
                    //子线程 因为ReceiveCilent()方法会阻断主线程 所以开辟子线程实现接收用户请求报文
                    //当前线程只负责与当前浏览器通信   
                    //System.Threading.ParameterizedThreadStart(ReceiveCilent) ReceiveCilent在线程上执行的方法
                    System.Threading.Thread thReceive = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ReceiveCilent));
                    thReceive.IsBackground = true;
                    //开启线程时将当前的cSocket传给ReceiveCilent  因为每个线程的cSocket不一样
                    thReceive.Start(cSocket);
                }
                catch { }                
            }
        }


        #endregion


        #region 5.0 接收浏览器的请求报文  在第4.0步被调用
        /// <summary>
        /// 接收浏览器的请求报文
        /// </summary>
        private void ReceiveCilent(object cSocket)
        {
            //因为每次浏览器向服务器请求时 cSocket不同,所以要转换为Socket型
            //当前线程只负责和当前浏览器通信 每个线程都会传一个cSocket进来 每个线程的cSocket不一样 所以tmpSocket所存储的变量不同 
            //所以在这里要转型
            Socket tmpSocket = cSocket as Socket;
            //申请1M的空间来存储请求报文信息
            byte[] receiveBuffer = new byte[1024 * 1024];
            string requestString = string.Empty;
            while (!isStop)
            {
                try
                {
                    //代码执行到这也会停止 等待用户的请求报文 
                    int len = tmpSocket.Receive(receiveBuffer);
                    //接收浏览器请求报文数据
                    //1.0 将请求报文数据转换为字符串赋值给requestString
                    requestString = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, len);
                    //tmpSocket.Receive(receiveBuffer);


                    //2.0 将浏览器请求报文在txtReceiveStr中显示
                    displayMsg(requestString);


                    //3.0 将请求报文送往ASP.NET框架处理机制
                    byte[] responseByte = IsApiRuntime.ProcessRequest(requestString);


                    //4.0 通过浏览器的连接套接字tmpSocket 的Send方法将响应报文数据反馈给浏览器
                    tmpSocket.Send(responseByte);
                }
                catch
                {


                }
            }


        }
        #endregion
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值