为了更加透彻理解 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 } }