之前的博客 利用C#制作简单服务器 介绍了一个可以搭建简单服务器的类,但是有一个问题,这个服务器完全是基于虚拟路径的,即请求的文件位置在服务器上是根本不存在的。如果只是将这个服务器应用于单个类型请求的响应肯定是不够的,我们需要将这个服务器弄成可以针对不同虚拟路径进行不同响应的,于是对代码进行了以下修改:
using System;
using System.Collections.Generic;
using System.Net;
namespace HttpWebServer
{
public delegate void RequestReceivedEventHandler(HttpListenerContext context);
public class HttpWebServer:IDisposable
{
protected HttpListener _listener;
protected bool _isListenerOn;
public event RequestReceivedEventHandler OnRequestReceived;
public HttpWebServer(HttpWebServerResponsor responsor)
{
OnRequestReceived += responsor.Response;
}
public void StartListening(string[] urlCollection)
{
_isListenerOn = true;
_listener = new HttpListener();
foreach (var i in urlCollection) _listener.Prefixes.Add(i);
_listener.Start();
Action requestLoop = new Action(delegate
{
while (_isListenerOn)
{
_listener.BeginGetContext(new AsyncCallback(delegate (IAsyncResult ar)
{
OnRequestReceived(_listener.EndGetContext(ar));
}), null).AsyncWaitHandle.WaitOne();
}
});
requestLoop.BeginInvoke(null, null);
}
public void StopListening()
{
if (_isListenerOn)
{
_isListenerOn = false;
if (_listener != null)
{
_listener.Stop();
_listener.Close();
_listener = null;
}
}
}
public void Dispose()
{
StopListening();
}
}
public class HttpWebServerResponsor
{
public RequestReceivedEventHandler errorResponseMethod;
private ServerCommandNode _rootNode;
public ServerCommandNode RootNode { get => _rootNode; }
public HttpWebServerResponsor()
{
_rootNode = new ServerCommandNode("");
}
public void Response(HttpListenerContext context)
{
string[] urlGroup = context.Request.RawUrl.Split('?')[0].Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
ServerCommandNode node = _rootNode;
RequestReceivedEventHandler responseMethod=null;
foreach (var i in urlGroup)
{
node = node[i];
if (node==null)
{
responseMethod = errorResponseMethod;
break;
}
}
if (node != null) responseMethod = node.RootResponseMethod;
responseMethod?.Invoke(context);
return;
}
}
public class ServerCommandNode
{
string _name;
Dictionary<string, ServerCommandNode> _serverNodes;
public RequestReceivedEventHandler RootResponseMethod;
public ServerCommandNode this[string nodeName] { get => _serverNodes[nodeName]; }
public void AddNode(string name, RequestReceivedEventHandler requestReceived = null)
{
_serverNodes.Add(name, new ServerCommandNode(name, requestReceived));
}
public ServerCommandNode(string name, RequestReceivedEventHandler requestReceived = null)
{
_name = name;
_serverNodes = new Dictionary<string, ServerCommandNode>();
RootResponseMethod = requestReceived;
}
}
}
使用方法:
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;
namespace HttpWebServer
{
public partial class Form1 : Form
{
private HttpWebServer webServer;
public Form1()
{
InitializeComponent();
HttpWebServerResponsor serverResponsor = new HttpWebServerResponsor();
serverResponsor.RootNode.AddNode("chat", Response_chat);
webServer = new HttpWebServer(serverResponsor);
webServer.StartListening(new string[] { "http://127.0.0.1:14285/" });
}
private void Response_chat(HttpListenerContext context)
{
var reader = new StreamReader(context.Request.InputStream);
var msg = reader.ReadToEnd();
reader.Dispose();
HttpListenerResponse response = context.Response;
string responseString = null;
var quaryString = context.Request.QueryString;
string userId = context.Request.QueryString["user"];
if (userId == null)
{
response.StatusCode = 233;
response.StatusDescription = "No user";
responseString = "error";
Invoke(new MethodInvoker(delegate
{
textBox1.Text += $"Anonymous:{msg}\r\n";
}));
}
else
{
Invoke(new MethodInvoker(delegate
{
textBox1.Text += $"{userId}:{msg}\r\n";
}));
response.StatusCode = 200;
responseString = "ok";
}
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}
}
}