【轮子狂魔】一个你不知道的HttpListener,玩出花样之基础篇(附带源码)_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 【轮子狂魔】一个你不知道的HttpListener,玩出花样之基础篇(附带源码)

【轮子狂魔】一个你不知道的HttpListener,玩出花样之基础篇(附带源码)

 2015/1/4 12:03:25  寻找和谐  程序员俱乐部  我要评论(0)
  • 摘要:这一次我们要玩什么?HttpListener:提供一个简单的、可通过编程方式控制的HTTP协议侦听器。(好吧,我承认这句是从MSDN上抄过来的)既然引子出来了,说明我们要开始玩Http请求了。那么我们基础篇要做的是,如何把一个html文件从服务器返回给客户端。一个Http请求我们需要做些什么?1.监听一个地址前缀,如:http://localhost/2.解析Url3.执行Url所代表的指令4.返回执行结果监听一个Http请求下面贴出的是主要的代码,实际源码中做了一些其他的处理
  • 标签:list 源码 一个 Ten HTTP
这一次我们要玩什么?

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

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

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

 

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

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

2.解析Url

3.执行Url所代表的指令

4.返回执行结果

 

监听一个Http请求

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

class="code_img_closed" src="/Upload/Images/2015010412/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('eb7781ca-7516-458b-b472-4f5e70b09108',event)" src="/Upload/Images/2015010412/2B1B950FA3DF188F.gif" alt="" />
 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/HttpListenerDemo

 

发表评论
用户名: 匿名