using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
public class HttpServer : IDisposable
{
private const string NotFoundResponse = "<!doctype html><html><body>Resource not found</body></html>";
private readonly HttpListener httpListener;
private readonly CancellationTokenSource cts = new CancellationTokenSource();
private readonly string prefixPath; private Task processingTask; public HttpServer(string listenerUriPrefix)
{
this.prefixPath = ParsePrefixPath(listenerUriPrefix);
this.httpListener = new HttpListener();
this.httpListener.Prefixes.Add(listenerUriPrefix);
} private static string ParsePrefixPath(string listenerUriPrefix)
{
var match = Regex.Match(listenerUriPrefix, @"http://(?:[^/]*)(?:\:\d+)?/(.*)");
if (match.Success)
{
return match.Groups[1].Value.ToLowerInvariant();
}
else
{
return string.Empty;
}
} public void Start()
{
this.httpListener.Start();
this.processingTask = Task.Factory.StartNew(async () => await ProcessRequests(), TaskCreationOptions.LongRunning);
} private async Task ProcessRequests()
{
while (!this.cts.IsCancellationRequested)
{
try
{
var context = await this.httpListener.GetContextAsync();
try
{
await ProcessRequest(context).ConfigureAwait(false);
context.Response.Close();
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.StatusDescription = "Internal Server Error";
context.Response.Close();
Console.WriteLine("Error processing HTTP request\n{0}", ex);
}
}
catch (ObjectDisposedException ex)
{
if ((ex.ObjectName == this.httpListener.GetType().FullName) && (this.httpListener.IsListening == false))
{
return; // listener is closed/disposed
}
Console.WriteLine("Error processing HTTP request\n{0}", ex);
}
catch (Exception ex)
{
HttpListenerException httpException = ex as HttpListenerException;
if (httpException == null || httpException.ErrorCode != 995)// IO operation aborted
{
Console.WriteLine("Error processing HTTP request\n{0}", ex);
}
}
}
} private Task ProcessRequest(HttpListenerContext context)
{
if (context.Request.HttpMethod.ToUpperInvariant() != "GET")
{
return WriteNotFound(context);
} var urlPath = context.Request.RawUrl.Substring(this.prefixPath.Length)
.ToLowerInvariant(); switch (urlPath)
{
case "/":
if (!context.Request.Url.ToString().EndsWith("/"))
{
context.Response.Redirect(context.Request.Url + "/");
context.Response.Close();
return Task.FromResult(0);
}
else
{
return WriteString(context, "Hello World!", "text/plain");
}
case "/favicon.ico":
return WriteFavIcon(context);
case "/ping":
return WritePong(context);
}
return WriteNotFound(context);
} private static Task WritePong(HttpListenerContext context)
{
return WriteString(context, "pong", "text/plain");
} private static async Task WriteFavIcon(HttpListenerContext context)
{
context.Response.ContentType = "image/png";
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
using (var stream = File.Open("icon.png", FileMode.Open))
{
var output = context.Response.OutputStream;
await stream.CopyToAsync(output);
}
} private static Task WriteNotFound(HttpListenerContext context)
{
return WriteString(context, NotFoundResponse, "text/plain", 404, "NOT FOUND");
} private static async Task WriteString(HttpListenerContext context, string data, string contentType,
int httpStatus = 200, string httpStatusDescription = "OK")
{
AddCORSHeaders(context.Response);
AddNoCacheHeaders(context.Response); context.Response.ContentType = contentType;
context.Response.StatusCode = httpStatus;
context.Response.StatusDescription = httpStatusDescription; var acceptsGzip = AcceptsGzip(context.Request);
if (!acceptsGzip)
{
using (var writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8, 4096, true))
{
await writer.WriteAsync(data).ConfigureAwait(false);
}
}
else
{
context.Response.AddHeader("Content-Encoding", "gzip");
using (GZipStream gzip = new GZipStream(context.Response.OutputStream, CompressionMode.Compress, true))
using (var writer = new StreamWriter(gzip, Encoding.UTF8, 4096, true))
{
await writer.WriteAsync(data).ConfigureAwait(false);
}
}
} private static bool AcceptsGzip(HttpListenerRequest request)
{
string encoding = request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(encoding))
{
return false;
} return encoding.Contains("gzip");
} private static void AddNoCacheHeaders(HttpListenerResponse response)
{
response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
response.Headers.Add("Pragma", "no-cache");
response.Headers.Add("Expires", "0");
} private static void AddCORSHeaders(HttpListenerResponse response)
{
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
} private void Stop()
{
cts.Cancel();
if (processingTask != null && !processingTask.IsCompleted)
{
processingTask.Wait();
}
if (this.httpListener.IsListening)
{
this.httpListener.Stop();
this.httpListener.Prefixes.Clear();
}
} public void Dispose()
{
this.Stop();
this.httpListener.Close();
using (this.cts) { }
using (this.httpListener) { }
}
}

利用HttpListener创建简单的HTTP服务的更多相关文章

  1. 通过HttpListener实现简单的Http服务

    使用HttpListener实现简单的Http服务 HttpListener提供一个简单的.可通过编程方式控制的 HTTP 协议侦听器.使用它可以很容易的提供一些Http服务,而无需启动IIS这类大型 ...

  2. 1.WCF学习--创建简单的WCF服务

    一.基本了解WCF 1.面向服务代表的是一种设计理念,和面向对象.面向组件一样,体现的是一种对关注点进行分解的思想,面向服务是和技术无关的 2.WCF需要依存一个运行着的宿主进程,服务寄宿就是为服务指 ...

  3. 利用WCF创建简单的RESTFul Service

    1):用VS2013创建一个WCF的工程,如下图所示: 2):我们来看一下默认状态下的config文件内容,这里的内容我们会再后续的步骤中进行修改 <?xml version="1.0 ...

  4. 使用C#创建简单的WCF服务

    一.开发环境 操作系统:Windows 10 开发环境:VS2015 编程语言:C# IIS版本:10.0.0.0 二.添加WCF服务.Internet Information Services(II ...

  5. 使用nomad && consul && fabio 创建简单的微服务系统

    具体每个组件的功能就不详细说明了 nomad 一个调度工具,consul 一个服务发现,健康检查多数据中心支持的工具 fabio 一个基于consul的负载均衡&&动态路由工具,对于集 ...

  6. 通过VS创建简单的WCF服务

    http://www.cnblogs.com/artech/archive/2007/09/15/893838.html http://www.topwcftutorials.net/2013/09/ ...

  7. 使用idea创建简单的webservice服务

     New project: 生成HelloWorld.wsdl: 配置好tomcat后还需要加入 Axis 的库: 启动后,访问http://localhost:8080/services: 点击He ...

  8. 使用Topshelf组件构建简单的Windows服务

    很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...

  9. c# 通过HttpListener创建HTTP服务

    在c#中可以利用HttpListener来自定义创建HTTP服务,通过http协议进行服务端与多个客户端之间的信息传递,并且可以做成windows系统服务,而不用寄宿在IIS上.以下为一个demo,分 ...

随机推荐

  1. spring boot学习笔记

    spring boot 是什么 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程. spring boot采用了“约定优于配置” ...

  2. SharePoint 2013 单一页面赋设计权限

    本文介绍SharePoint的使用中,断开单一页面权限,给用户编辑权限以及操作中遇到的问题,希望给相关需要的人一个参考. 1.首先进入页面库,找到我们的页面,进入共享,如下图: 2.在弹出的窗口中选择 ...

  3. Oracle SQL Tips

    左连接的同时只输出关联表的一条记录 WITH X AS (SELECT 1 ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL ...

  4. Android——五大布局

    Android的五大布局分为: 线性布局 相对布局 帧布局 绝对布局 表格布局 一.线性布局 线性布局在开发中使用最多,具有垂直方向与水平方向的布局方式 通过设置属性"android:ori ...

  5. iOS扫一扫功能开发

    之前很多二维码扫描都是基于zxing做的,但是zxing用起来真的很麻烦,又一直不更新.随着iOS6退出历史舞台,终于可以使用iOS7以后,用系统的AVFoundation做的二维码扫描器了. 初始化 ...

  6. iOS网络-02-数据解析(JSON与XML)

    数据交互格式 服务器返回给用户的数据,通常是以下两种方式: JSON XML JSON 一种轻量级的数据数据格式,体积比XML小,是服务器返回给移动端通常采用的格式 用使用JSON文件中的数据,需要对 ...

  7. Saiku 下载,安装

    Saiku是一个模块化的开源分析套件,它提供轻量级的OLAP(联机分析处理),并且可嵌入.可扩展.可配置. 主页:http://community.meteorite.bi 如何安装摘自: http: ...

  8. 设计模式 --- 模型-视图-控制器(Model View Controller)

    模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程 ...

  9. debian7 请把标有“Debian GNU/Linux 7.1.0 _Wheezy_ - Official amd64 DVD Binary-1 20130615-23:06”的盘片插入驱动器“/media/cdrom/”再按回车键

    有时候,在通过apt-get install 安装软件的时候,会出现: 更换介质:请把标有“Debian GNU/Linux 7.1.0 _Wheezy_ - Official amd64 DVD B ...

  10. JavaScript Patterns 2.10 Naming Conventions

    1. Capitalizing Constructors var adam = new Person(); 2. Separating Words camel case - type the word ...