基於C#完成一個最簡略的HTTP辦事器實例。本站提示廣大學習愛好者:(基於C#完成一個最簡略的HTTP辦事器實例)文章只能為提供參考,不一定能成為您想要的結果。以下是基於C#完成一個最簡略的HTTP辦事器實例正文
本文具體剖析了基於C#完成一個最簡略的HTTP辦事器的辦法。分享給年夜家供年夜家參考。詳細以下:
1、簡介
本文用C#完成了一個最簡略的HTTP辦事器類,你可以將它嵌入到本身的項目中,或許也能夠浏覽代碼來進修關於HTTP協定的常識。
2、配景
高機能的WEB運用普通都架設在壯大的WEB辦事器上,例如IIS, Apache, 和Tomcat。但是,HTML長短常靈巧的UI標志說話,也就是說任何運用和後端辦事都可以供給HTML的生成支撐。在這個小小的例子中,像IIS,、 Apache如許的辦事器消費的資本太年夜了,我們須要本身完成一個簡略的HTTP辦事器,將它嵌入到我們的運用頂用來處置WEB要求。我們僅須要一個類就 可以完成了,很簡略。
3、代碼完成
起首我們往返顧一下若何應用類,然後我們再來剖析完成的詳細細節。這裡我們創立了一個繼續於HttpServer的類,並完成了handleGETRequest 和handlePOSTRequest 這兩個籠統辦法:
public class MyHttpServer : HttpServer {
public MyHttpServer(int port)
: base(port) {
}
public override void handleGETRequest(HttpProcessor p) {
Console.WriteLine("request: {0}", p.http_url);
p.writeSuccess();
p.outputStream.WriteLine("<html><body><h1>test server</h1>");
p.outputStream.WriteLine("Current Time: " + DateTime.Now.ToString());
p.outputStream.WriteLine("url : {0}", p.http_url);
p.outputStream.WriteLine("<form method=post action=/form>");
p.outputStream.WriteLine("<input type=text name=foo value=foovalue>");
p.outputStream.WriteLine("<input type=submit name=bar value=barvalue>");
p.outputStream.WriteLine("</form>");
}
public override void handlePOSTRequest(HttpProcessor p, StreamReader inputData) {
Console.WriteLine("POST request: {0}", p.http_url);
string data = inputData.ReadToEnd();
p.outputStream.WriteLine("<html><body><h1>test server</h1>");
p.outputStream.WriteLine("<a href=/test>return</a><p>");
p.outputStream.WriteLine("postbody: <pre>{0}</pre>", data);
}
}
當開端處置一個簡略的要求時,我們就須要零丁啟動一個線程來監聽一個端口,好比8080端口:
HttpServer httpServer = new MyHttpServer(8080);
Thread thread = new Thread(new ThreadStart(httpServer.listen));
thread.Start();
假如你編譯運轉這個項目,你會在閱讀器http://localhost:8080地址下看到頁面上生成的示例內容。讓我們來簡略看一下這個HTTP辦事器引擎是怎樣完成的。
這個WEB辦事器由兩個組件組成,一個是擔任啟動TcpListener來監聽指定端口的HttpServer類,而且用 AcceptTcpClient()辦法輪回處置TCP銜接要求,這是處置TCP銜接的第一步。然後要求達到“已指定“的端口,接著就會創立一對新的端 口,用來初始化客戶端到辦事器真個TCP銜接。這對端口就是TcpClient的session,如許便可以堅持我們的主端口可以持續吸收新的銜接要求。 從上面的代碼中我們可以看到,每次監聽法式都邑創立一個新的TcpClien,HttpServer類又會創立一個新的HttpProcessor,然 後啟動一個線程來操作。HttpServer類中還包括兩個籠統辦法,你必需完成這兩個辦法。
public abstract class HttpServer {
protected int port;
TcpListener listener;
bool is_active = true;
public HttpServer(int port) {
this.port = port;
}
public void listen() {
listener = new TcpListener(port);
listener.Start();
while (is_active) {
TcpClient s = listener.AcceptTcpClient();
HttpProcessor processor = new HttpProcessor(s, this);
Thread thread = new Thread(new ThreadStart(processor.process));
thread.Start();
Thread.Sleep(1);
}
}
public abstract void handleGETRequest(HttpProcessor p);
public abstract void handlePOSTRequest(HttpProcessor p, StreamReader inputData);
}
如許,一個新的tcp銜接就在本身的線程中被HttpProcessor處置了,HttpProcessor的任務就是准確解析HTTP頭,而且掌握准確完成的籠統辦法。上面我們來看看HTTP頭的處置進程,HTTP要求的第一行代碼以下:
GET /myurl HTTP/1.0
在設置完process()的輸出和輸入後,HttpProcessor就會挪用parseRequest()辦法。
public void parseRequest() {
String request = inputStream.ReadLine();
string[] tokens = request.Split(' ');
if (tokens.Length != 3) {
throw new Exception("invalid http request line");
}
http_method = tokens[0].ToUpper();
http_url = tokens[1];
http_protocol_versionstring = tokens[2];
Console.WriteLine("starting: " + request);
}
HTTP要求由3部門構成,所以我們只須要用string.Split()辦法將它們朋分成3部門便可,接上去就是吸收息爭析來自客戶真個HTTP頭 信息,頭信息中的每行數據是以Key-Value(鍵-值)情勢保留,空行表現HTTP頭信息停止標記,我們代碼頂用readHeaders辦法來讀取 HTTP頭信息:
public void readHeaders() {
Console.WriteLine("readHeaders()");
String line;
while ((line = inputStream.ReadLine()) != null) {
if (line.Equals("")) {
Console.WriteLine("got headers");
return;
}
int separator = line.IndexOf(':');
if (separator == -1) {
throw new Exception("invalid http header line: " + line);
}
String name = line.Substring(0, separator);
int pos = separator + 1;
while ((pos < line.Length) && (line[pos] == ' ')) {
pos++; // 過濾失落一切空格
}
string value = line.Substring(pos, line.Length - pos);
Console.WriteLine("header: {0}:{1}",name,value);
httpHeaders[name] = value;
}
}
到這裡,我們曾經懂得了若何處置簡略的GET和POST要求,它們分離被分派給准確的handler處置法式。在本例中,發送數據的時刻有一個辣手的 成績須要處置,那就是要求頭信息中包括發送數據的長度信息content-length,當我們願望子類HttpServer中的 handlePOSTRequest辦法可以或許准確處置數據時,我們須要將數據長度content-length信息一路放入數據流中,不然發送端會由於等 待永久弗成能達到的數據和壅塞期待。我們用了一種看起來不那末優雅但異常有用的辦法來處置這類情形,行將數據發送給POST處置辦法前先把數據讀入到 MemoryStream中。這類做法不太幻想,緣由以下:假如發送的數據很年夜,乃至是上傳一個文件,那末我們將這些數據緩存在內存就不那末適合乃至是不 能夠的。幻想的辦法是限制post的長度,好比我們可以將數據長度限制為10MB。
這個簡略單純版HTTP辦事器另外一個簡化的處所就是content-type的前往值,在HTTP協定中,辦事器老是會將數據的MIME-Type發送給 客戶端,告知客戶端本身須要吸收甚麼類型的數據。在writeSuccess()辦法中,我們看到,辦事器老是發送text/html類型,假如你須要加 入其他的類型,你可以擴大這個辦法。
願望本文所述對年夜家的C#法式設計有所贊助。