【轮子狂魔】抛弃IIS,打造个性的Web Server

8/3/2015来源:C#应用人气:731

【轮子狂魔】抛弃IIS,打造个性的Web Server - WebAPI/Lua/MVC(附带源码

引言

此篇是《【轮子狂魔】抛弃IIS,向天借个HttpListener - 基础篇(附带源码)》的续篇,也可以说是提高篇,如果你对HttpListener不甚了解的话,建议先看下基础篇。

这次玩的东西有点多了,大致分为如下几个方向:

1.支持静态页面

2.Ur映射l执行方法

3.Url映射执行Lua脚本

4.模仿MVC中的C

这些东西有什么用?

支持静态页面:这个纯属玩具吧,只是基础篇作为引子的一个简单示例而已。

Url映射执行方法:类似Web API,可以提供一些基于Http协议的交互方式。

Url映射执行Lua脚本:与上面一样,不同的是,在某些场景下更合适,比如业务频繁变动、频繁发布。Lua脚本我就不细说了,不清楚的可以百度一下,是个很好玩的东西。

模仿MVC中的C:这个实例只是想说基于HttpListener我们可以做很多事情,如果你对asp.net、MVC很熟悉,你可以做个整整的Web Server出来,甚至做个Web框架都可以。

那么除了这些还可以做什么?

其实太多了,比如反向代理、负载均衡、黑名单等等,你都可以做。如果你有兴趣可以跟帖讨论 ^_^

改造HttpServer支持横向扩展

抽离出一个接口:HttpImplanter

1 interface HttpImplanter2     {3         void Start();4         void Stop();5         void MakeHttpPRefix(HttpListener server);6         ReturnCode ProcessRequest(HttpListenerContext context);7         byte[] CreateReturnResult(HttpListenerContext context, ReturnCode result);8     }
View Code

改造HttpServer的一些执行细节

  1 /// <summary>  2     /// 可接收Http请求的服务器  3     /// </summary>  4     class HttpServer  5     {  6         Thread _httpListenThread;  7   8         /// <summary>  9         /// HttpServer是否已经启动 10         /// </summary> 11         volatile bool _isStarted = false; 12  13         /// <summary> 14         /// 线程是否已经结束 15         /// </summary> 16         volatile bool _terminated = false; 17         volatile bool _ready = false; 18         volatile bool _isRuning = false; 19         HttpImplanter _httpImplanter; 20  21         public void Start(HttpImplanter httpImplanter) 22         { 23             if (!HttpListener.IsSupported) 24             { 25                 Logger.Exit("不支持HttpListener!"); 26             } 27  28             if (_isStarted) 29             { 30                 return; 31             } 32             _isStarted = true; 33             _ready = false; 34             _httpImplanter = httpImplanter;  35  36             RunHttpServerThread(); 37  38             while (!_ready) ; 39         } 40  41         private void RunHttpServerThread() 42         { 43             _httpListenThread = new Thread(new ThreadStart(() => 44             { 45                 HttpListener server = new HttpListener(); 46                 try 47                 { 48                     _httpImplanter.MakeHttpPrefix(server); 49                     server.Start(); 50                 } 51                 catch (Exception ex) 52                 { 53                     Logger.Exit("无法启动服务器监听,请检查网络环境。"); 54                 } 55  56                 _httpImplanter.Start(); 57  58                 IAsyncResult result = null; 59                 while (!_terminated) 60                 { 61                     while (result == null || result.IsCompleted) 62                     { 63                         result = server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server); 64                     } 65                     _ready = true; 66                     Thread.Sleep(10); 67                 } 68  69                 server.Stop(); 70                 server.Abort(); 71                 server.Close(); 72                 _httpImplanter.Stop(); 73             } 74             )); 75  76             _httpListenThread.IsBackground = true; 77             _httpListenThread.Start(); 78         } 79  80         private void ProcessHttpRequest(IAsyncResult iaServer) 81         { 82             HttpListener server = iaServer.AsyncState as HttpListener; 83             HttpListenerContext context = null; 84             try 85             { 86                 context = server.EndGetContext(iaServer); 87                 Logger.Info("接收请求" + context.Request.Url.ToString()); 88                 //判断上一个操作未完成,即返回服务器正忙,并开启一个新的异步监听 89                 if (_isRuning) 90                 { 91                     Logger.Info("正在处理请求,已忽略请求" + context.Request.Url.ToString()); 92                     RetutnResponse(context, _httpImplanter.CreateReturnResult(context, new ReturnCode((int)CommandResult.ServerIsBusy, EnumHelper.GetEnumDescription(CommandResult.ServerIsBusy)))); 93                     server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server); 94                     return; 95                 } 96  97                 _isRuning = true; 98                 server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server); 99             }100             catch101             {102                 Logger.Warning("服务器已关闭!");103                 return;104             }105 106             string scriptName = new UrlHelper(context.Request.Url).ScriptName;107             byte[] resultBytes = null;108             if (scriptName.ToLower().EndsWith(".html")||scriptName == "favicon.ico")109             {110                 string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", scriptName);111                 if (File.Exists(filePath))112                 {113                     resultBytes = File.ReadAllBytes(filePath);114                 }115                 else116                 {117                     resultBytes = _httpImplanter.CreateReturnResult(context, new ReturnCode((int)CommandResult.FileNotExists, EnumHelper.GetEnumDescription(CommandResult.FileNotExists)));118                 }119             }120             else121             {122                 ReturnCode result = _httpImplanter.ProcessRequest(context);123                 resultBytes = _httpImplanter.CreateReturnResult(context, result);124             }125             RetutnResponse(context, resultBytes);126             _isRuning = false;127         }128 129         private static void RetutnResponse(HttpListenerContext context, byte[] resultBytes)130         {131             context.Response.ContentLength64 = resultBytes.Length;132             System.IO.Stream output = context.Response.OutputStream;133             try134             {135                 output.Write(resultBytes, 0, resultBytes.Length);136                 output.Close();137             }138             catch139             {140                 Logger.Warning("客户端已经关闭!");141             }142         }143 144         public void Stop()145         {146             if (!_isStarted)147             {148                 return;149             }150 151             _terminated = true;152             _httpListenThread.Join();153 154             _isStarted = false;155         }156 157     }
View Code

Url映射执行方法

1.继承HttpImplanter

2.增加监听前缀,用于过滤Url

3.创建返回结果

3.1 解析Url

3.2 定位访问的类

3.3 执行Url所表示的方法