因为第一次在博客园发表随笔,不太会用,这个笔记是我之前在印象笔记中写好的,然后直接copy过来,有兴趣自己做一个IIS服务器的小伙伴们可以参照下面的流程做一次,也可以叫我要源代码,不过要做完,我觉得话费一下午的时间必须是要的,完成之后,可能你对ASP.NET框架的具体运作流程会有更加深的了解
1.服务器简单界面如图所示 ()
1.访问静态页面的时候 http://127.0.0.1:8088/web/1.html
class="en-media" src="https://app.yinxiang.com/shard/s20/sh/74169863-2e25-494c-8da5-63e77225af18/87600fe054a306b76548797048b991a5/res/48588401-7649-411a-b281-d5206dda50df.png?resizeSmall&width=832" alt="" name="48588401-7649-411a-b281-d5206dda50df" />
2.访问动态页面,例如 http://127.0.0.1:8088/Pages/index.aspx
项目文件布局:
各个类之间的关系(简单):
1.可以更改服务器IP地址已经端口
2.点击启动服务器的时候,显示服务器已经启动,同时利用
socket进行
循环监听
3.利用浏览器访问服务器下面的网页的时候,就显示少量的响应报文头跟响应报文体
二、需要用到的知识点
- socket进行浏览器与服务器端的通讯
- 浏览器与服务器的get与post相关内容
- asp.net框架处理流程以及aspx页面生命周期
- 接口与工厂
项目步骤
- 新建项目,创建一个winform程序,同时创建好相关的控件,点击启动服务器,在窗体初始化的时候,加入下列代码,TextBox.CheckForIllegalCrossThreadCalls = false;目的就是为了显示请求报文的消息,textbox控件新建一个线程来接收,而不用窗体的主线程;
- 点击启动的时候 1.新建一个SocketServer类(本质是一台服务器),然后server.start()启动服务器,不停监听来自浏览器的访问页面请求
- 这样我们先新建一个
类,因为要用到线程,socket,以及端口等,先引入命名空间
,然后创建相关的属性已经socket对象
,同时创建构造函数,目的在form传入输入的IP地址,端口,以及显示消息的方法
,接下来写一个Start()方法
因为线程创建的时候要传入一个方法或者是委托,那我就新建一个方法吧,用来循环接收客户端(浏览器)发来的信息 这时接收用户端也要新建一个线程,同时传入一个receiveMsg方法,传入的是什么?传入就是客户端socekt对象,下面又来创建receiveMsg方法接下来定义PR方法,根据ASP.NET框架处理机制,是交由ISAPIRuntime处理
- 新建一个ISAPIRuntime类,其实它也不自己出来requestMessage,交由HttpRuntime处理
- 新建HttpRuntime类,根据ASP.NET框架处理机制,首先创建上下文对象HTTPContext,(截图)
- 新建HttpContext类,根据我们创建HttpRequest、HttpResponse、HttpServerUtility、interface IHttpHandle 这些类和接口,作用分别是请求上下文对象,响应上下文对象,Server属性,接口是给后面的httpApplication,动态和静态处理页面的类来继承,目的只有一个,通过反射,谁创建了接口,他就是那个类的对象,也就是对应着是动态页面,还是静态页面。
- HttpContext 类:
- HttpRequest 类:定义httpMoethod、Url、HttpVersion、UrlExtention四个属性,同时利用构造函数初始化HttpRequest对象
- HttpResponse 类:
- HttpRequest _request; //根据请求报文,创建响应的响应报文
Dictionary <int , string> statuDic = new Dictionary < int, string >();//服务器状态码 如404
System.Text. StringBuilder sbContent = new StringBuilder(500); //用来接收write()写入的字符串
/// <summary>
/// 构造函数,初始化服务器状态码
/// </summary>
/// <param name="request"></param>
public HttpResponse(HttpRequest request)
{
this ._request = request;
statuDic.Add(200, "OK" );
statuDic.Add(302, "Found" );
statuDic.Add(404, "File Not Found" );
statuDic.Add(500, "Error" );
}
//刚开始给状态码赋初始值statuCode=200;
private int statuCode = 200;
/// <summary>
/// 状态码,如200
/// </summary>
public int StatuCode
{
get { return statuCode; }
set { statuCode = value ; }
}
private string statuStr;
/// <summary>
/// 状态码对应的应为表示符,如OK,FOUND
/// </summary>
public string StatuStr
{
get { return statuStr; }
set { statuStr = value ; }
}
private byte [] content = new byte [0];
/// <summary>
/// 响应报文的流
/// </summary>
public byte [] Content
{
get { return content; }
set { content = value ; }
}
/// <summary>
/// 响应报文长度
/// </summary>
public int ContentLength
{
get
{
return content.Length;
}
}
/// <summary>
/// 根据请求报文的后缀名,如.jpg对应image/jpeg
/// </summary>
public string ContenType
{
get
{
string contentType = "" ;
switch (_request.UrlExtention)
{
case ".jpg" :
case ".png" :
case ".gif" :
contentType = "image/jpeg" ;
break ;
case ".html" :
case ".htm" :
contentType = "text/html" ;
break ;
case ".aspx" :
case ".ashx" :
case "styd" :
contentType = "text/html" ;
break ;
case ".css" :
contentType = "text/css" ;
break ;
case ".js" :
contentType = "application/javascript" ;
break ;
default :
contentType = "text/html" ;
break ;
}
return contentType;
}
}
public string Server
{
get { return "MyIISServer"; }
}
/// <summary>
/// 服务器响应报文的write()方法,相当于content.Response.Write
/// </summary>
/// <param name="str"></param>
public void Write( string str)
{
sbContent.Append(str);
content = System.Text.Encoding .UTF8.GetBytes(sbContent.ToString());
}
System.Text. StringBuilder sbHead = new StringBuilder(200);
/// <summary>
/// 组装响应报文体,返回byte数组
/// </summary>
/// <returns></returns>
public byte [] GetResponseByts()
{
sbHead.AppendLine(_request.HttpVersion + " " + this .StatuCode + " " + this .StatuStr);
sbHead.AppendLine( "Server:myWebServer" );
sbHead.AppendLine( "Content-Length:" + this.ContentLength);
sbHead.AppendLine( "Content-Type:" + this.ContenType + " ;charset=utf-8");
sbHead.AppendLine( "" );//头和体之间的空白行
byte [] head = System.Text.Encoding .UTF8.GetBytes(sbHead.ToString());
byte [] resultByte = new byte[head.Length + ContentLength];
head.CopyTo(resultByte, 0);
Content.CopyTo(resultByte, head.Length);
return resultByte;
}
}
- HttpServerUtility 类
- 创建上面的类完毕之后,回到HttpContext类,代码不多,引入,同时做好属性封装之后,在构造函数里面进行初始化
- 这样的话我们的httpContext对象就创建完毕,根据,我们回到HttpRuntime类,我们创建一个HttpApplicationFactory 工厂类,同时还要创建HttpApplication类,前面是一个工厂类,后面才是我们创建HttpApplication对象,开始跑我们的事件管道
- HttpApplicationFactory 类
- HttpApplication 类:要继承IHttpHandle接口,实现接口的PR方法,这时候就真正来到我们的事件管道,因为ASP.NET框架有19个事件,实现起来十分复杂,因此在这里我只是简单地执行第8个事件,还有是11跟12个事件之间的PR方法,在第8个事件管道的时候,创建页面类对象,考虑到页面有动态页面跟静态页面,创建的依据就是context.request发来的UrlExtention,因此我创建一个PageProcessFactory页面类工厂,举例有三个页面类对象
- PageProcessFactory 类 同时创建者三个类,都要继承IHttpHandle接口,实现PR方法
- HttpProcessImg 图片生成生成类
- HttpProcessstatic 静态页面生成类
- HttpProcessDyn 动态页面生成类
- 上面的页面类创建完成后,回到PageProcessFactory工厂类,根据context.request.UrlExtention来创建相应的页面类对象,存到handle中
- 这样的话页面类对象创建完成,我们再次回到HttpApplication这个类,执行PageProcessFactory工厂的方法,得到页面类对象,同时进行事件管道的方法,这里只是写第8个事件管道跟11与12事件管道的内容
- 执行完事件管道之后,也就是执行完httpcontext,再次回到HttpRuntime类,这时就可以将响应报文respon发回给ISAPIRuntime类,再由这个类返回给SocketServer服务器
- 这时就基本完成了浏览器请求服务器上面的网页,回到SocketServer服务器上,将请求报文头显示出来
- 回到winform,
- 这样我们就差不多完成了自己写的小小的IIS服务器,将我们自己写好的html页面文件复制到项目中,这里有个小小细节要注意,因为运行的时候程序是在bin/debug里面运行,因此右击随便一个文件--属性这样文件就自动复制到bin目录下面,程序就会找到文件