这一次我们要玩什么?

先声明一下,由于这篇是基础篇主要是通过这篇文章让大家对使用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 - 基础篇(附带源码)的更多相关文章

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

    引言 此篇是<[轮子狂魔]抛弃IIS,向天借个HttpListener - 基础篇(附带源码)>的续篇,也可以说是提高篇,如果你对HttpListener不甚了解的话,建议先看下基础篇. ...

  2. 【轮子狂魔】手把手教你自造Redis Client

    为什么做Redis Client? Redis Client顾名思义,redis的客户端,主要是封装了一些对于Redis的操作. 而目前用的比较广泛的 ServiceStack.Redis 不学好,居 ...

  3. 【轮子狂魔】打造简易无配置的IoC

    如何指定Business Event和Command之间的关系? 既然是基于惯例优先原则,那么我们首先需要定义一个惯例: 1.调度事件和调度处理器之间是一对多关系(多对多的话,相信你看完了以后应该会知 ...

  4. 「造个轮子」——cicada 源码分析

    前言 两天前写了文章<「造个轮子」--cicada(轻量级 WEB 框架)> 向大家介绍了 cicada 之后收到很多反馈,也有许多不错的建议. 同时在 GitHub 也收获了 80 几颗 ...

  5. 【轮子狂魔】手把手教你用JS给博客动态增加目录 - 超级懒人版

    动态显示目录的作用 不用每次写博客的时候繁琐的人工整理目录,又可以动态浮动在右下角,方便快速跳到感兴趣的位置同时也可以快速的对文章内容有一个大概的了解. 实现原理 首先根据个人喜好,我习惯了用 h1 ...

  6. 【轮子狂魔】WeChatAPI 开源系统架构详解

    如果使用WeChatAPI,它扮演着什么样的角色? 从图中我们可以看到主要分为3个部分: 1.业务系统 2.WeChatAPI: WeChatWebAPI,主要是接收微信服务器请求: WeChatAP ...

  7. WebForm(一)——IIS服务器、开发方式和简单基础

    一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据 ...

  8. WebForm——IIS服务器、开发方式和简单基础

    一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据 ...

  9. CassiniDev源码学习 - 可替代IIS的单机Web Form解决方案

    最近一个项目是将web版的程序,改为单机版.话说这个web版号称当年十几个人用了至少3个月的时间开发,后来三年还不断有修改,而现在要在1个月内由一个人完成,这简直是不可能完成的任务!直觉告诉我,重写肯 ...

随机推荐

  1. Excel截取特定字符后面的值

    应该用到三个字符串函数:LEFT.RIGHT.MID 1.LEFT函数: 用法:LEFT(要提取字符所在单元格,从左侧开始提取的个数) 例如:=LEFT(A1,2) 意思是从A1单元格提取前两个字符. ...

  2. 铁乐学python_day20_面向对象编程2

    面向对象的组合用法 软件重用的重要方式除了继承之外还有另外一种方式,即:组合 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合. 例:人狗大战,人类绑定上武器来对狗进行攻击: # 定 ...

  3. C++ 读书笔记1

    c++ 笔记1 body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding ...

  4. 面对对象程序设计_task2_1001.A+B Format (20)

    Someting about 1001.A+B Format (20) 问题描述及我所写的代码:click here → My Task 看到这个题目的时候,我的想法很简单,直接判断直接输出,因为给定 ...

  5. Bottle + WebUploader 修改Bottle框架从而大文件上传实现方案

    Bottle 是个轻量级的Web框架,小巧又强大,真不愧是个轻量级的框架.可扩展性非常好,可以扩展很多功能,但是有些功能就不得不自己动手修改了. Bottle:http://www.bottlepy. ...

  6. 使用yii的layout,加入<?php echo $content; ?>这句话时,它会自动在子页面上面添加一个div包裹

    使用yii的layout,加入<?php echo $content; ?>这句话时,它会自动在子页面上面添加一个div包裹,而且div的id命名为id=content,这个和已有id重复 ...

  7. TensorFlow函数(八)tf.control_dependencies()

    tf.control_dependencies(control_inputs) 此函数指定某些操作执行的依赖关系 返回一个控制依赖的上下文管理器,使用 with 关键字可以让在这个上下文环境中的操作都 ...

  8. 神经网络中Epoch、Iteration、Batchsize相关理解

    batch 深度学习的优化算法,说白了就是梯度下降.每次的参数更新有两种方式. 第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度.这种方法每更新一次参数都要把数据集里的所有样 ...

  9. MapReduce经典入门小案例

    /** * 单词统计 * @author fengmingyue * */ public class WordCount { public static void main(String[] args ...

  10. 愤怒的小鸟【$DP$优化】

    卡常的状压\(DP\),愤怒的小鸟. 其实本来是个很水的状压\(DP\),但因为最后三个点\(n=18\),成功地把我的不可能达到的下界为\(\Omega(2^nn^2)\),紧确的上界为\(O(2^ ...