Created
September 18, 2022 06:25
-
-
Save ichengzi/50c8a3732d4174928d21efb78f97e4ba to your computer and use it in GitHub Desktop.
c# simple http server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
namespace demo | |
{ | |
public class MimeType | |
{ | |
public static string GetOrDefault(string fileExtension, string defaultMime) | |
{ | |
if (_mimeTypeMappings.ContainsKey(fileExtension)) | |
return _mimeTypeMappings[fileExtension]; | |
return defaultMime; | |
} | |
/// <summary> | |
/// Mime Type conversion table | |
/// </summary> | |
public static IDictionary<string, string> _mimeTypeMappings = | |
new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) | |
{ | |
{ ".asf", "video/x-ms-asf" }, | |
{ ".asx", "video/x-ms-asf" }, | |
{ ".avi", "video/x-msvideo" }, | |
{ ".bin", "application/octet-stream" }, | |
{ ".cco", "application/x-cocoa" }, | |
{ ".crt", "application/x-x509-ca-cert" }, | |
{ ".css", "text/css" }, | |
{ ".deb", "application/octet-stream" }, | |
{ ".der", "application/x-x509-ca-cert" }, | |
{ ".dll", "application/octet-stream" }, | |
{ ".dmg", "application/octet-stream" }, | |
{ ".ear", "application/java-archive" }, | |
{ ".eot", "application/octet-stream" }, | |
{ ".exe", "application/octet-stream" }, | |
{ ".flv", "video/x-flv" }, | |
{ ".gif", "image/gif" }, | |
{ ".hqx", "application/mac-binhex40" }, | |
{ ".htc", "text/x-component" }, | |
{ ".htm", "text/html" }, | |
{ ".html", "text/html" }, | |
{ ".ico", "image/x-icon" }, | |
{ ".img", "application/octet-stream" }, | |
{ ".iso", "application/octet-stream" }, | |
{ ".jar", "application/java-archive" }, | |
{ ".jardiff", "application/x-java-archive-diff" }, | |
{ ".jng", "image/x-jng" }, | |
{ ".jnlp", "application/x-java-jnlp-file" }, | |
{ ".jpeg", "image/jpeg" }, | |
{ ".jpg", "image/jpeg" }, | |
{ ".js", "application/x-javascript" }, | |
{ ".json", "application/json" }, | |
{ ".mml", "text/mathml" }, | |
{ ".mng", "video/x-mng" }, | |
{ ".mov", "video/quicktime" }, | |
{ ".mp3", "audio/mpeg" }, | |
{ ".mp4", "video/mp4" }, | |
{ ".mpeg", "video/mpeg" }, | |
{ ".mpg", "video/mpeg" }, | |
{ ".msi", "application/octet-stream" }, | |
{ ".msm", "application/octet-stream" }, | |
{ ".msp", "application/octet-stream" }, | |
{ ".pdb", "application/x-pilot" }, | |
{ ".pdf", "application/pdf" }, | |
{ ".pem", "application/x-x509-ca-cert" }, | |
{ ".pl", "application/x-perl" }, | |
{ ".pm", "application/x-perl" }, | |
{ ".png", "image/png" }, | |
{ ".prc", "application/x-pilot" }, | |
{ ".ra", "audio/x-realaudio" }, | |
{ ".rar", "application/x-rar-compressed" }, | |
{ ".rpm", "application/x-redhat-package-manager" }, | |
{ ".rss", "text/xml" }, | |
{ ".run", "application/x-makeself" }, | |
{ ".sea", "application/x-sea" }, | |
{ ".shtml", "text/html" }, | |
{ ".sit", "application/x-stuffit" }, | |
{ ".swf", "application/x-shockwave-flash" }, | |
{ ".tcl", "application/x-tcl" }, | |
{ ".tk", "application/x-tcl" }, | |
{ ".txt", "text/plain" }, | |
{ ".war", "application/java-archive" }, | |
{ ".wbmp", "image/vnd.wap.wbmp" }, | |
{ ".wmv", "video/x-ms-wmv" }, | |
{ ".xml", "text/xml" }, | |
{ ".xpi", "application/x-xpinstall" }, | |
{ ".zip", "application/zip" }, | |
}; | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Ctrip.IO; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
namespace demo | |
{ | |
public static class MyHttpServer | |
{ | |
private static List<SimpleHttpServer> _servers = new List<SimpleHttpServer>(); | |
public static String Start(string path, int port = -1) | |
{ | |
if (port == -1) | |
port = SimpleHttpServer.GetNotUsedPort(); | |
var server = new SimpleHttpServer(path, port); | |
_servers.Add(server); | |
return server.Url; | |
} | |
public static void Stop() | |
{ | |
foreach (var server in _servers) | |
{ | |
try | |
{ | |
log.Info("Stop_Http_Server", $"{server.Url} {server.HostDir}"); | |
server.Stop(); | |
} | |
catch (Exception ex) | |
{ | |
log.Error("Stop_Http_Server", $"{server.Url} {server.HostDir}" + ex); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Net; | |
using System.Threading; | |
using System.IO; | |
using System.Net.Sockets; | |
using System.Threading.Tasks; | |
namespace demo | |
{ | |
public class SimpleHttpServer | |
{ | |
private volatile bool _stop = false; | |
private readonly string _rootDirectory; | |
private readonly int _port; | |
private HttpListener _listener; | |
public string Url { get; } | |
public string HostDir { get { return _rootDirectory; } } | |
public SimpleHttpServer(string path, int port) | |
{ | |
_stop = false; | |
_rootDirectory = path; | |
_port = port; | |
// Url = "http://127.0.0.1:" + _port + "/"; | |
Url = "http://localhost:" + _port + "/"; | |
Start(); | |
} | |
/// <summary> | |
/// Stop server and dispose all functions. | |
/// </summary> | |
public void Stop() | |
{ | |
_stop = true; | |
_listener.Stop(); | |
} | |
private void Start() | |
{ | |
_listener = new HttpListener(); | |
_listener.Prefixes.Add(Url); | |
_listener.Start(); | |
// reactor 网络编程模型. 这里用 单reactor多线程模型 | |
// https://www.cnblogs.com/xiaolincoding/p/14706824.html | |
// 新起一个线程 接受请求 | |
new Thread(() => | |
{ | |
while (!_stop) | |
{ | |
try | |
{ | |
HttpListenerContext context = _listener.GetContext(); | |
// 读取请求完成后,传给 线程池 完成后续的处理 | |
Task.Factory.StartNew(() => { Process(context); }); | |
} | |
catch (Exception ex) when (ex is InvalidOperationException || ex is ObjectDisposedException) | |
{ | |
Console.WriteLine("http listener error," + ex.ToString()); | |
break; | |
} | |
catch (Exception ex) | |
{ | |
// log error | |
} | |
} | |
}).Start(); | |
} | |
/// <summary> | |
/// Process an individual request. Handles only static file based requests | |
/// </summary> | |
/// <param name="context"></param> | |
private void Process(HttpListenerContext context) | |
{ | |
HttpListenerResponse response = context.Response; | |
var request = context.Request; | |
string filename = context.Request.Url.AbsolutePath; | |
Console.WriteLine("request fileName :" + filename); | |
// 支持传入超时参数, 模拟接口响应时间太长 | |
var delayStr = request.QueryString.Get("__delayMillisecond__"); | |
int delay; | |
if (Int32.TryParse(delayStr, out delay) && delay > 0) | |
{ | |
Console.WriteLine("url contain delay flag, delay milliSeconds: " + delay); | |
Thread.Sleep(delay); | |
} | |
// 中文文件名称url转码 | |
filename = System.Web.HttpUtility.UrlDecode(filename.Substring(1), Encoding.UTF8); | |
if (string.IsNullOrEmpty(filename)) | |
{ | |
foreach (string indexFile in DefaultDocuments) | |
{ | |
if (File.Exists(Path.Combine(_rootDirectory, indexFile))) | |
{ | |
filename = indexFile; | |
break; | |
} | |
} | |
} | |
filename = Path.Combine(_rootDirectory, filename); | |
var fileExtension = Path.GetExtension(filename); | |
if (string.IsNullOrWhiteSpace(fileExtension)) | |
{ | |
// 文件扩展名默认处理 | |
if (request.ContentType.Contains("application/json")) | |
fileExtension = ".json"; | |
else | |
fileExtension = ".html"; | |
filename += fileExtension; | |
} | |
if (!File.Exists(filename)) | |
{ | |
response.StatusCode = (int)HttpStatusCode.NotFound; | |
response.OutputStream.Close(); | |
return; | |
} | |
try | |
{ | |
Stream fileStream = new FileStream(filename, FileMode.Open); | |
//Adding permanent http response headers | |
string mime = MimeType.GetOrDefault(fileExtension, "application/octet-stream"); | |
response.ContentType = mime; | |
if (fileStream.Length > 1024 * 16) | |
response.SendChunked = true; | |
else | |
response.ContentLength64 = fileStream.Length; | |
response.AddHeader("Date", DateTime.Now.ToString("r")); | |
response.AddHeader("Last-Modified", File.GetLastWriteTime(filename).ToString("r")); | |
response.StatusCode = (int)HttpStatusCode.OK; | |
fileStream.CopyTo(response.OutputStream); | |
fileStream.Close(); | |
response.OutputStream.Flush(); | |
} | |
catch (Exception ex) | |
{ | |
response.StatusCode = (int)HttpStatusCode.InternalServerError; | |
} | |
response.OutputStream.Close(); | |
} | |
public static int GetNotUsedPort() | |
{ | |
//get an empty port | |
TcpListener listener = new TcpListener(IPAddress.Loopback, 0); | |
listener.Start(); | |
int port = ((IPEndPoint)listener.LocalEndpoint).Port; | |
listener.Stop(); | |
return port; | |
} | |
private string[] DefaultDocuments = | |
{ | |
"index.html", | |
"index.htm", | |
"default.html", | |
"default.htm" | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment