zoukankan      html  css  js  c++  java
  • 【轮子狂魔】抛弃IIS,向天借个HttpListener

    这一次我们要玩什么?

     先声明一下,由于这篇是基础篇主要是通过这篇文章让大家对使用HttpListener响应Http请求有个大概了解,所以正式的花样轮子在下一篇推出,敬请期待 ^_^

     嗯哼,还有,我标题党了一下,看完我这个系列的话,在特定场景下可抛弃IIS,但如果完全抛弃IIS就不要想咯 ^_^

     HttpListener:提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。(好吧,我承认这句是从MSDN上抄过来的)

     既然引子出来了,说明我们要开始玩Http请求了。

     那么我们基础篇要做的是,如何把一个 html 文件从服务器返回给客户端。

    一个Http请求我们需要做些什么?

    1.监听一个地址前缀,如:http://localhost/

    2.解析Url

    3.执行Url所代表的指令

    4.返回执行结果

    监听一个Http请求

     下面贴出的是主要的代码,实际源码中做了一些其他的处理,比如多线程防止界面卡死、HttpListener运行环境检测、资源释放、容错等等。

     1                 HttpListener server = new HttpListener();
     2                 try
     3                 {
     4                     MakeHttpPrefix(server);
     5                     server.Start();
     6                 }
     7                 catch (Exception ex)
     8                 {
     9                     Logger.Exit("无法启动服务器监听,请检查网络环境。");
    10                 }
    11 
    12                 IAsyncResult result = null;
    13                 while (!_terminated)
    14                 {
    15                     while (result == null || result.IsCompleted)
    16                     {
    17                         result = server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server);
    18                     }
    19                     _ready = true;
    20                     Thread.Sleep(10);
    21                 }
    22 
    23                 server.Stop();
    24                 server.Abort();
    25                 server.Close();
    View Code
    解析Url

    解析Url时需要做几个事情:

    1.Url的长度限制

    2.是否包含特殊字符

    3.拆分指令与参数

      1     /// <summary>
      2     /// Url辅助类:对Url进行初步的解析
      3     /// </summary>
      4     public class UrlHelper
      5     {
      6         const int MAX_URI_LENGTH = 512;
      7         string _scriptName = string.Empty;
      8         CommandResult _parseResult = CommandResult.Success;
      9         NameValueCollection _parameters = new NameValueCollection();
     10         char[] _uriInvalidChar = new char[] { '/', '\' };
     11         char[] _pathInvalidChar = new char[] { '/', '\', ':', '*', '?', '"', '<', '>', '|' };
     12         public Uri _uri = null;
     13 
     14         public string ScriptName
     15         {
     16             get { return _scriptName; }
     17         }
     18 
     19         public NameValueCollection Parameters
     20         {
     21             get { return _parameters; }
     22         }
     23 
     24         public CommandResult ParseResult
     25         {
     26             get { return _parseResult; }
     27         }
     28 
     29         public UrlHelper(Uri originalUri)
     30         {
     31             _uri = originalUri;
     32 
     33             if (IsUriLengthError())
     34             {
     35                 return;
     36             }
     37 
     38             if (CheckPathAndQuery())
     39             {
     40                 ParsePathAndQuery();
     41             }
     42         }
     43 
     44         private bool IsUriLengthError()
     45         {
     46             if (_uri == null || _uri.ToString().Length > MAX_URI_LENGTH)
     47             {
     48                 _parseResult = CommandResult.UrlTooLong;
     49                 return true;
     50             }
     51             return false;
     52         }
     53 
     54         private bool CheckPathAndQuery()
     55         {
     56             string pathAndQuery = _uri.PathAndQuery.Substring(1);
     57 
     58             if (IsUrlInvalidChar(pathAndQuery))
     59             {
     60                 return false;
     61             }
     62 
     63             if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= 0)
     64             {
     65                 _parseResult = CommandResult.UrlInvalidChar;
     66                 return false;
     67             }
     68             else if (pathAndQuery.Length == 0)
     69             {
     70                 _parseResult = CommandResult.NoExistsMethod;
     71                 return false;
     72             }
     73 
     74             string[] splitPathAndQuery = new string[] { };
     75             if (IsFileNameInvalidChar(pathAndQuery, splitPathAndQuery))
     76             {
     77                 return false;
     78             }
     79 
     80             return true;
     81 
     82         }
     83 
     84         private bool IsFileNameInvalidChar(string pathAndQuery, string[] splitPathAndQuery)
     85         {
     86             splitPathAndQuery = pathAndQuery.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
     87             if (splitPathAndQuery[0].IndexOfAny(_pathInvalidChar) >= 0)
     88             {
     89                 _parseResult = CommandResult.FileNameInvalidChar;
     90                 return true;
     91             }
     92             return false;
     93         }
     94 
     95         private bool IsUrlInvalidChar(string pathAndQuery)
     96         {
     97             if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= 0)
     98             {
     99                 _parseResult = CommandResult.UrlInvalidChar;
    100                 return true;
    101             }
    102             return false;
    103         }
    104 
    105         private void ParsePathAndQuery()
    106         {
    107             string[] splitPathAndQuery = _uri.PathAndQuery.Substring(1).Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
    108             SetScriptNameAndParameters(splitPathAndQuery);
    109         }
    110 
    111         private void SetScriptNameAndParameters(string[] splitPathAndQuery)
    112         {
    113             _scriptName = splitPathAndQuery[0];
    114 
    115             if (splitPathAndQuery.Length > 1)
    116             {
    117                 _parameters = HttpUtility.ParseQueryString(splitPathAndQuery[1], Encoding.UTF8);
    118             }
    119         }
    120     }
    View Code
    执行Url所代表的指令和返回执行结果

    1.判断Url的请求文件后缀是否支持

    2.检索本地文件

    3.如果文件存在则返回文件,不存在则返回异常(此处在后续扩展活增加更多可变性,比如一些动态执行方法等)

    PS:由于此处代码涉及几个方法就不贴了,直接看源码吧。(ProcessHttpRequest 方法)

    有图有真相

     请求一个简单的Hello World的html文件,此处有个细节,就是浏览器会发送ico请求。聪明的你如果想要显示ico应该知道怎么办吧 ^_^

    请求一个不支持的后缀,如:htm

    下一次我们玩什么?

    1.丰富一下请求文件类型

    2.支持执行方法的请求

    3.在HttpListner里玩一玩LUA脚本

    最后,我要放源码了 ^_^

    http://git.oschina.net/doddgu/WebServerDemo

  • 相关阅读:
    mysql数据库 --数据类型、约束条件
    并发编程 --线程
    并发编程 --进程
    MySQL数据库 --基础
    网络编程之 TCP-UDP的详细介绍
    网络编程之 OSI七层协议
    python 元类、单例模式
    python 面向对象_多态、内置方法、反射
    Python 面向对象_继承、组合
    简单工厂设计模式
  • 原文地址:https://www.cnblogs.com/doddgu/p/lunzikuangmo_httplistener_simple.html
Copyright © 2011-2022 走看看