【轮子狂魔】抛弃IIS,向天借个HttpListener - 基础篇(附带源码)
| 这一次我们要玩什么? |
先声明一下,由于这篇是基础篇主要是通过这篇文章让大家对使用HttpListener响应Http请求有个大概了解,所以正式的花样轮子在下一篇推出,敬请期待 ^_^
嗯哼,还有,我标题党了一下,看完我这个系列的话,在特定场景下可抛弃IIS,但如果完全抛弃IIS就不要想咯 ^_^
HttpListener:提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。(好吧,我承认这句是从MSDN上抄过来的)
既然引子出来了,说明我们要开始玩Http请求了。
那么我们基础篇要做的是,如何把一个 html 文件从服务器返回给客户端。
| 一个Http请求我们需要做些什么? |
1.监听一个地址前缀,如:http://localhost/
2.解析Url
3.执行Url所代表的指令
4.返回执行结果
| 监听一个Http请求 |
下面贴出的是主要的代码,实际源码中做了一些其他的处理,比如多线程防止界面卡死、HttpListener运行环境检测、资源释放、容错等等。
HttpListener server = new HttpListener();
try
{
MakeHttpPrefix(server);
server.Start();
}
catch (Exception ex)
{
Logger.Exit("无法启动服务器监听,请检查网络环境。");
} IAsyncResult result = null;
while (!_terminated)
{
while (result == null || result.IsCompleted)
{
result = server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server);
}
_ready = true;
Thread.Sleep();
} server.Stop();
server.Abort();
server.Close();
| 解析Url |
解析Url时需要做几个事情:
1.Url的长度限制
2.是否包含特殊字符
3.拆分指令与参数
/// <summary>
/// Url辅助类:对Url进行初步的解析
/// </summary>
public class UrlHelper
{
const int MAX_URI_LENGTH = ;
string _scriptName = string.Empty;
CommandResult _parseResult = CommandResult.Success;
NameValueCollection _parameters = new NameValueCollection();
char[] _uriInvalidChar = new char[] { '/', '\\' };
char[] _pathInvalidChar = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|' };
public Uri _uri = null; public string ScriptName
{
get { return _scriptName; }
} public NameValueCollection Parameters
{
get { return _parameters; }
} public CommandResult ParseResult
{
get { return _parseResult; }
} public UrlHelper(Uri originalUri)
{
_uri = originalUri; if (IsUriLengthError())
{
return;
} if (CheckPathAndQuery())
{
ParsePathAndQuery();
}
} private bool IsUriLengthError()
{
if (_uri == null || _uri.ToString().Length > MAX_URI_LENGTH)
{
_parseResult = CommandResult.UrlTooLong;
return true;
}
return false;
} private bool CheckPathAndQuery()
{
string pathAndQuery = _uri.PathAndQuery.Substring(); if (IsUrlInvalidChar(pathAndQuery))
{
return false;
} if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= )
{
_parseResult = CommandResult.UrlInvalidChar;
return false;
}
else if (pathAndQuery.Length == )
{
_parseResult = CommandResult.NoExistsMethod;
return false;
} string[] splitPathAndQuery = new string[] { };
if (IsFileNameInvalidChar(pathAndQuery, splitPathAndQuery))
{
return false;
} return true; } private bool IsFileNameInvalidChar(string pathAndQuery, string[] splitPathAndQuery)
{
splitPathAndQuery = pathAndQuery.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
if (splitPathAndQuery[].IndexOfAny(_pathInvalidChar) >= )
{
_parseResult = CommandResult.FileNameInvalidChar;
return true;
}
return false;
} private bool IsUrlInvalidChar(string pathAndQuery)
{
if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= )
{
_parseResult = CommandResult.UrlInvalidChar;
return true;
}
return false;
} private void ParsePathAndQuery()
{
string[] splitPathAndQuery = _uri.PathAndQuery.Substring().Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
SetScriptNameAndParameters(splitPathAndQuery);
} private void SetScriptNameAndParameters(string[] splitPathAndQuery)
{
_scriptName = splitPathAndQuery[]; if (splitPathAndQuery.Length > )
{
_parameters = HttpUtility.ParseQueryString(splitPathAndQuery[], Encoding.UTF8);
}
}
}
| 执行Url所代表的指令和返回执行结果 |
1.判断Url的请求文件后缀是否支持
2.检索本地文件
3.如果文件存在则返回文件,不存在则返回异常(此处在后续扩展活增加更多可变性,比如一些动态执行方法等)
PS:由于此处代码涉及几个方法就不贴了,直接看源码吧。(ProcessHttpRequest 方法)
| 有图有真相 |
请求一个简单的Hello World的html文件,此处有个细节,就是浏览器会发送ico请求。聪明的你如果想要显示ico应该知道怎么办吧 ^_^

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

| 下一次我们玩什么? |
1.丰富一下请求文件类型
2.支持执行方法的请求
3.在HttpListner里玩一玩LUA脚本
最后,我要放源码了 ^_^
http://git.oschina.net/doddgu/WebServerDemo
【轮子狂魔】抛弃IIS,向天借个HttpListener - 基础篇(附带源码)的更多相关文章
- 【轮子狂魔】抛弃IIS,打造个性的Web Server - WebAPI/Lua/MVC(附带源码)
引言 此篇是<[轮子狂魔]抛弃IIS,向天借个HttpListener - 基础篇(附带源码)>的续篇,也可以说是提高篇,如果你对HttpListener不甚了解的话,建议先看下基础篇. ...
- 【轮子狂魔】手把手教你自造Redis Client
为什么做Redis Client? Redis Client顾名思义,redis的客户端,主要是封装了一些对于Redis的操作. 而目前用的比较广泛的 ServiceStack.Redis 不学好,居 ...
- 【轮子狂魔】打造简易无配置的IoC
如何指定Business Event和Command之间的关系? 既然是基于惯例优先原则,那么我们首先需要定义一个惯例: 1.调度事件和调度处理器之间是一对多关系(多对多的话,相信你看完了以后应该会知 ...
- 「造个轮子」——cicada 源码分析
前言 两天前写了文章<「造个轮子」--cicada(轻量级 WEB 框架)> 向大家介绍了 cicada 之后收到很多反馈,也有许多不错的建议. 同时在 GitHub 也收获了 80 几颗 ...
- 【轮子狂魔】手把手教你用JS给博客动态增加目录 - 超级懒人版
动态显示目录的作用 不用每次写博客的时候繁琐的人工整理目录,又可以动态浮动在右下角,方便快速跳到感兴趣的位置同时也可以快速的对文章内容有一个大概的了解. 实现原理 首先根据个人喜好,我习惯了用 h1 ...
- 【轮子狂魔】WeChatAPI 开源系统架构详解
如果使用WeChatAPI,它扮演着什么样的角色? 从图中我们可以看到主要分为3个部分: 1.业务系统 2.WeChatAPI: WeChatWebAPI,主要是接收微信服务器请求: WeChatAP ...
- WebForm(一)——IIS服务器、开发方式和简单基础
一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据 ...
- WebForm——IIS服务器、开发方式和简单基础
一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据 ...
- CassiniDev源码学习 - 可替代IIS的单机Web Form解决方案
最近一个项目是将web版的程序,改为单机版.话说这个web版号称当年十几个人用了至少3个月的时间开发,后来三年还不断有修改,而现在要在1个月内由一个人完成,这简直是不可能完成的任务!直觉告诉我,重写肯 ...
随机推荐
- CSS一个属性,让图片后的文字垂直居中,效果看得见
困扰我多年的疑难,终于解决了.哈哈哈,太爽了 背景 页面经常遇到,图片后面的文字显示在图片的中间部位,也就是说文字图片垂直居中. <div class="banner"> ...
- 铁乐学python_day03-作业
1.有变量name = "aleX leNb" 完成如下操作: 移除name变量对应的值两边的空格,并输出处理结果 n1 = name.strip() print(n1) 结果:a ...
- shell study
目录 shell记录 执行脚本 变量使用 注释 shell传递参数 运算符 echo printf test 流程控制 if ... else ... for while until case 跳出循 ...
- December 01st 2016 Week 49th Thursday
Life is a maze and love is a riddle. 生活是个迷宫,爱情是个谜语. I am lost in both. Can you provide me some guida ...
- Alpha 冲刺报告(6/10)
Alpha 冲刺报告(6/10) 队名:洛基小队 峻雄(组长) 已完成:实现角色的移动. 明日计划:关于角色的属性设计. 剩余任务:角色的属性脚本 困难:角色的属性以及具体的编码 ---------- ...
- 【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家
[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真 ...
- TensorFlow函数(六)初始值生成函数
1.常量生成函数 tf.constant(value, dtype) 生成一个初始值为常量value的数组 value:指定的常量 dtype:数据类型 tf.zeros(shape, dtype) ...
- OpenStack Grizzly详细安装指导
一.环境介绍: 控制节点 eth0 (10.10.10.51), eth1 (192.168.100.51) 网络节点 eth0 (10.10.10.52), eth1 (10.20.20.52), ...
- git checkout -b
创建分支: $ git branch mybranch切换分支: $ git checkout mybranch创建并切换分支: $ git checkout -b mybranch 更新master ...
- springboot不使用内置tomcat启动,用jetty或undertow
Spring Boot启动程序通常使用Tomcat作为默认的嵌入式服务器.如果需要更改 - 您可以排除Tomcat依赖项并改为包含Jetty或Undertow: jetty配置: <depend ...