時間:2023-05-24 04:12:01 | 來源:網(wǎng)站運營
時間:2023-05-24 04:12:01 來源:網(wǎng)站運營
自己動手實現(xiàn)網(wǎng)絡(luò)服務(wù)器(Web Server):class Program{ static void Main(string[] args) { string port = "8080"; HttpListener httpListener = new HttpListener(); httpListener.Prefixes.Add(string.Format("http://+:{0}/", port)); httpListener.Start(); httpListener.BeginGetContext(new AsyncCallback(GetContext), httpListener); //開始異步接收request請求 Console.WriteLine("監(jiān)聽端口:" + port); Console.Read(); } static void GetContext(IAsyncResult ar) { HttpListener httpListener = ar.AsyncState as HttpListener; HttpListenerContext context = httpListener.EndGetContext(ar); //接收到的請求context(一個環(huán)境封裝體) httpListener.BeginGetContext(new AsyncCallback(GetContext), httpListener); //開始 第二次 異步接收request請求 HttpListenerRequest request = context.Request; //接收的request數(shù)據(jù) HttpListenerResponse response = context.Response; //用來向客戶端發(fā)送回復(fù) response.ContentType = "html"; response.ContentEncoding = Encoding.UTF8; using (Stream output = response.OutputStream) //發(fā)送回復(fù) { byte[] buffer = Encoding.UTF8.GetBytes("要返回的內(nèi)容"); output.Write(buffer, 0, buffer.Length); } }}
這個簡單的代碼已經(jīng)可以實現(xiàn)用于小白機器人的網(wǎng)絡(luò)請求處理了,因為大致只用到GET和POST兩種HTTP方法,只需要在GetContext方法里判斷GET、POST方法,然后分別給出響應(yīng)就可以了。/// <summary>/// MIME類型/// </summary>public Dictionary<string, string> MIME_Type = new Dictionary<string, string>(){ { "htm", "text/html" }, { "html", "text/html" }, { "php", "text/html" }, { "xml", "text/xml" }, { "json", "application/json" }, { "txt", "text/plain" }, { "js", "application/x-javascript" }, { "css", "text/css" }, { "bmp", "image/bmp" }, { "ico", "image/ico" }, { "png", "image/png" }, { "gif", "image/gif" }, { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, { "webp", "image/webp" }, { "zip", "application/zip"}, { "*", "*/*" }};
劇透一下:其中有PHP類型是我們后面要使用CGI接入的方式使我們的服務(wù)器支持PHP。/// <summary>/// 啟動本地網(wǎng)頁服務(wù)器/// </summary>/// <param name="webroot">網(wǎng)站根目錄</param>/// <returns></returns>public bool Start(string webroot){ //觸發(fā)事件 if (OnServerStart != null) OnServerStart(httpListener); WebRoot = webroot; try { //監(jiān)聽端口 httpListener.Prefixes.Add("http://+:" + port.ToString() + "/"); httpListener.Start(); httpListener.BeginGetContext(new AsyncCallback(onWebResponse), httpListener); //開始異步接收request請求 } catch (Exception ex) { Qdb.Error(ex.Message, QDebugErrorType.Error, "Start"); return false; } return true;}
現(xiàn)在把網(wǎng)頁服務(wù)器的核心處理代碼貼出來。/// <summary>/// 網(wǎng)頁服務(wù)器相應(yīng)處理/// </summary>/// <param name="ar"></param>private void onWebResponse(IAsyncResult ar){ byte[] responseByte = null; //響應(yīng)數(shù)據(jù) HttpListener httpListener = ar.AsyncState as HttpListener; HttpListenerContext context = httpListener.EndGetContext(ar); //接收到的請求context(一個環(huán)境封裝體) httpListener.BeginGetContext(new AsyncCallback(onWebResponse), httpListener); //開始 第二次 異步接收request請求 //觸發(fā)事件 if (OnGetRawContext != null) OnGetRawContext(context); HttpListenerRequest request = context.Request; //接收的request數(shù)據(jù) HttpListenerResponse response = context.Response; //用來向客戶端發(fā)送回復(fù) //觸發(fā)事件 if (OnGetRequest != null) OnGetRequest(request, response); if (rawUrl == "" || rawUrl == "/") //單純輸入域名或主機IP地址 fileName = WebRoot + @"/index.html"; else if (rawUrl.IndexOf('.') == -1) //不帶擴展名,理解為文件夾 fileName = WebRoot + @"/" + rawUrl.SubString(1) + @"/index.html"; else { int fileNameEnd = rawUrl.IndexOf('?'); if (fileNameEnd > -1) fileName = rawUrl.Substring(1, fileNameEnd - 1); fileName = WebRoot + @"/" + rawUrl.Substring(1); } //處理請求文件名的后綴 string fileExt = Path.GetExtension(fileName).Substring(1); if (!File.Exists(fileName)) { responseByte = Encoding.UTF8.GetBytes("404 Not Found!"); response.StatusCode = (int)HttpStatusCode.NotFound; } else { try { responseByte = File.ReadAllBytes(fileName); response.StatusCode = (int)HttpStatusCode.OK; } catch (Exception ex) { Qdb.Error(ex.Message, QDebugErrorType.Error, "onWebResponse"); response.StatusCode = (int)HttpStatusCode.InternalServerError; } } if (MIME_Type.ContainsKey(fileExt)) response.ContentType = MIME_Type[fileExt]; else response.ContentType = MIME_Type["*"]; response.Cookies = request.Cookies; //處理Cookies response.ContentEncoding = Encoding.UTF8; using (Stream output = response.OutputStream) //發(fā)送回復(fù) { try { output.Write(responseByte, 0, responseByte.Length); } catch (Exception ex) { Qdb.Error(ex.Message, QDebugErrorType.Error, "onWebResponse"); response.StatusCode = (int)HttpStatusCode.InternalServerError; } }}
這樣就可以提供基本的網(wǎng)頁訪問了,經(jīng)過測試,使用Bootstrap,Pure等前端框架的網(wǎng)頁都可以完美訪問,性能方面一般般。(在QFramework的封裝中我做了一點性能優(yōu)化,有一點提升)我覺得要在性能方面做提升還是要在多線程處理這方面做優(yōu)化,由于篇幅關(guān)系,就不把多線程版本的代碼貼出來了。/// <summary>/// 是否開啟PHP功能/// </summary>public bool PHP_CGI_Enabled = true;/// <summary>/// PHP執(zhí)行文件路徑/// </summary>public string PHP_CGI_Path = "php-cgi";
接下來在網(wǎng)頁服務(wù)的核心代碼里做PHP支持的處理。//PHP處理string phpCgiOutput = "";Action phpProc = new Action(() =>{ try { string argStr = ""; if (request.HttpMethod == "GET") { if (rawUrl.IndexOf('?') > -1) argStr = rawUrl.Substring(rawUrl.IndexOf('?')); } else if (request.HttpMethod == "POST") { using (StreamReader reader = new StreamReader(request.InputStream)) { argStr = reader.ReadToEnd(); } } Process p = new Process(); p.StartInfo.CreateNoWindow = false; //不顯示窗口 p.StartInfo.RedirectStandardOutput = true; //重定向輸出 p.StartInfo.RedirectStandardInput = false; //重定向輸入 p.StartInfo.UseShellExecute = false; //是否指定操作系統(tǒng)外殼進程啟動程序 p.StartInfo.FileName = PHP_CGI_Path; p.StartInfo.Arguments = string.Format("-q -f {0} {1}", fileName, argStr); p.Start(); StreamReader sr = p.StandardOutput; while (!sr.EndOfStream) { phpCgiOutput += sr.ReadLine() + Environment.NewLine; } responseByte = sr.CurrentEncoding.GetBytes(phpCgiOutput); } catch (Exception ex) { Qdb.Error(ex.Message, QDebugErrorType.Error, "onWebResponse->phpProc"); response.StatusCode = (int)HttpStatusCode.InternalServerError; }});if (fileExt == "php" && PHP_CGI_Enabled){ phpProc();}else{ if (!File.Exists(fileName)) { responseByte = Encoding.UTF8.GetBytes("404 Not Found!"); response.StatusCode = (int)HttpStatusCode.NotFound; } else { try { responseByte = File.ReadAllBytes(fileName); response.StatusCode = (int)HttpStatusCode.OK; } catch (Exception ex) { Qdb.Error(ex.Message, QDebugErrorType.Error, "onWebResponse"); response.StatusCode = (int)HttpStatusCode.InternalServerError; } }}
這樣就實現(xiàn)了基于PHP-CGI的PHP支持了,經(jīng)過測試,基本的php頁面都可以支持,但是需要使用curl和xml這類擴展的暫時還沒辦法。需要做更多的工作。關(guān)鍵詞:服務(wù),網(wǎng)絡(luò),動手,實現(xiàn)
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。