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