原文地址:https://www.cnblogs.com/mq0036/p/6656888.html
最近有個web的小項目,但公司的電腦無法安裝IIS,所以就想自己來實現個Web server服務器,原本想了下,也就是socket處理http請求,於是就在博客園中搜索了“socket實現web server”,結果還真搜索到一些文章,於是從中找了幾個做參考,如下:
C#中自己動手創建一個Web Server(非Socket實現)
其他的這里就不一一列出了,感興趣的可以自己搜索看看。
所以我根據他們的代碼,然后自己在修改符合自己使用的情況,初次版本就出來了,代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets;namespace socket_webServer
{
class Program
{
static Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //偵聽socket
static string webRoot = @"C:\Users\jack\Desktop</span>";
static string defaultPage = "index.html,home.html";</span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] args) { webRoot </span>= <span style="color: #800000;">@"</span><span style="color: #800000;">C:\_jack\DevCode</span><span style="color: #800000;">"</span><span style="color: #000000;">; _socket.Bind(</span><span style="color: #0000ff;">new</span> IPEndPoint(IPAddress.Any, <span style="color: #800080;">8080</span><span style="color: #000000;">)); _socket.Listen(</span><span style="color: #800080;">100</span><span style="color: #000000;">); _socket.BeginAccept(</span><span style="color: #0000ff;">new</span> AsyncCallback(OnAccept), _socket); <span style="color: #008000;">//</span><span style="color: #008000;">開始接收來自瀏覽器的http請求(其實是socket連接請求)</span> writeLog(<span style="color: #800000;">"</span><span style="color: #800000;">Socket Web Server 已啟動監聽!</span><span style="color: #800000;">"</span> + Environment.NewLine + <span style="color: #800000;">"</span><span style="color: #800000;"> 監聽端口:</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> ((IPEndPoint)_socket.LocalEndPoint).Port); Console.ReadKey(); } </span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span> <span style="color: #808080;">///</span><span style="color: #008000;"> 接受處理http的請求 </span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span> <span style="color: #808080;">///</span> <span style="color: #808080;"><param name="ar"></param></span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> OnAccept(IAsyncResult ar) { </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Socket socket </span>= ar.AsyncState <span style="color: #0000ff;">as</span><span style="color: #000000;"> Socket; Socket web_client </span>= socket.EndAccept(ar); <span style="color: #008000;">//</span><span style="color: #008000;">接收到來自瀏覽器的代理socket </span><span style="color: #008000;">//</span><span style="color: #008000;">NO.1 並行處理http請求</span> socket.BeginAccept(<span style="color: #0000ff;">new</span> AsyncCallback(OnAccept), socket); <span style="color: #008000;">//</span><span style="color: #008000;">開始下一次http請求接收 (此行代碼放在NO.2處時,就是串行處理http請求,前一次處理過程會阻塞下一次請求處理)</span> <span style="color: #0000ff;">byte</span>[] recv_Buffer = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[<span style="color: #800080;">1024</span> * <span style="color: #800080;">640</span><span style="color: #000000;">]; </span><span style="color: #0000ff;">int</span> recv_Count = web_client.Receive(recv_Buffer); <span style="color: #008000;">//</span><span style="color: #008000;">接收瀏覽器的請求數據</span> <span style="color: #0000ff;">string</span> recv_request = Encoding.UTF8.GetString(recv_Buffer, <span style="color: #800080;">0</span><span style="color: #000000;">, recv_Count); writeLog(</span><span style="color: #800000;">"</span><span style="color: #800000;">Data Request : </span><span style="color: #800000;">"</span> + recv_request); <span style="color: #008000;">//</span><span style="color: #008000;">將請求顯示到界面 </span><span style="color: #008000;">//</span><span style="color: #008000;">Resolve(recv_request, web_client); </span><span style="color: #008000;">//</span><span style="color: #008000;">解析、路由、處理</span> <span style="color: #0000ff;">byte</span>[] cont =<span style="color: #000000;"> pageHandle(RouteHandle(recv_request)); sendPageContent(cont, web_client); </span><span style="color: #008000;">//</span><span style="color: #008000;">NO.2 串行處理http請求</span>
}
catch (Exception ex)
{
writeLog("處理http請求時出現異常!" + Environment.NewLine + "\t" + ex.Message);
}
}</span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> sendPageContent(<span style="color: #0000ff;">byte</span><span style="color: #000000;">[] pageContent, Socket response) { </span><span style="color: #0000ff;">string</span> statusline = <span style="color: #800000;">"</span><span style="color: #800000;">HTTP/1.1 200 OK\r\n</span><span style="color: #800000;">"</span>; <span style="color: #008000;">//</span><span style="color: #008000;">狀態行</span> <span style="color: #0000ff;">byte</span>[] statusline_to_bytes =<span style="color: #000000;"> Encoding.UTF8.GetBytes(statusline); </span><span style="color: #0000ff;">string</span> content = <span style="color: #800000;">"</span><span style="color: #800000;"><html></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"><head></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"><title>socket webServer -- Login</title></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"></head></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"><body></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"><div style=\"text-align:center\"></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;">歡迎您!</span><span style="color: #800000;">"</span> + <span style="color: #800000;">""</span> + <span style="color: #800000;">"</span><span style="color: #800000;">,今天是 </span><span style="color: #800000;">"</span> + DateTime.Now.ToLongDateString() + <span style="color: #800000;">"</span><span style="color: #800000;"></div></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"></body></span><span style="color: #800000;">"</span> + <span style="color: #800000;">"</span><span style="color: #800000;"></html></span><span style="color: #800000;">"</span>; <span style="color: #008000;">//</span><span style="color: #008000;">內容</span> <span style="color: #0000ff;">byte</span>[] content_to_bytes =<span style="color: #000000;"> pageContent; </span><span style="color: #0000ff;">string</span> header = <span style="color: #0000ff;">string</span>.Format(<span style="color: #800000;">"</span><span style="color: #800000;">Content-Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, content_to_bytes.Length); </span><span style="color: #0000ff;">byte</span>[] header_to_bytes = Encoding.UTF8.GetBytes(header); <span style="color: #008000;">//</span><span style="color: #008000;">應答頭</span>
response.Close();response.Send(statusline_to_bytes); </span><span style="color: #008000;">//</span><span style="color: #008000;">發送狀態行</span> response.Send(header_to_bytes); <span style="color: #008000;">//</span><span style="color: #008000;">發送應答頭</span> response.Send(<span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[] { (<span style="color: #0000ff;">byte</span>)<span style="color: #800000;">'</span><span style="color: #800000;">\r</span><span style="color: #800000;">'</span>, (<span style="color: #0000ff;">byte</span>)<span style="color: #800000;">'</span><span style="color: #800000;">\n</span><span style="color: #800000;">'</span> }); <span style="color: #008000;">//</span><span style="color: #008000;">發送空行</span> response.Send(content_to_bytes); <span style="color: #008000;">//</span><span style="color: #008000;">發送正文(html)</span>
} </span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span> <span style="color: #808080;">///</span> <span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span> <span style="color: #808080;">///</span> <span style="color: #808080;"><param name="request"></param></span> <span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> RouteHandle(<span style="color: #0000ff;">string</span><span style="color: #000000;"> request) { </span><span style="color: #0000ff;">string</span> retRoute = <span style="color: #800000;">""</span><span style="color: #000000;">; </span><span style="color: #0000ff;">string</span>[] strs = request.Split(<span style="color: #0000ff;">new</span> <span style="color: #0000ff;">string</span>[] { <span style="color: #800000;">"</span><span style="color: #800000;">\r\n</span><span style="color: #800000;">"</span> }, StringSplitOptions.None); <span style="color: #008000;">//</span><span style="color: #008000;">以“換行”作為切分標志</span> <span style="color: #0000ff;">if</span> (strs.Length > <span style="color: #800080;">0</span>) <span style="color: #008000;">//</span><span style="color: #008000;">解析出請求路徑、post傳遞的參數(get方式傳遞參數直接從url中解析)</span>
{
string[] items = strs[0].Split(' '); //items[1]表示請求url中的路徑部分(不含主機部分)
string pageName = items[1];
string post_data = strs[strs.Length - 1]; //最后一項
//Dictionary<string, string> dict = ParameterHandle(strs);
retRoute = pageName + (post_data.Length > 0 ? "?" + post_data : "");
}</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> retRoute; } </span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span> <span style="color: #808080;">///</span><span style="color: #008000;"> 按照HTTP協議格式,解析瀏覽器發送的請求字符串 </span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span> <span style="color: #808080;">///</span> <span style="color: #808080;"><param name="strs"></param></span> <span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span> <span style="color: #0000ff;">static</span> Dictionary<<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">string</span>> ParameterHandle(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] strs) { Dictionary</span><<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">string</span>> param = <span style="color: #0000ff;">new</span> Dictionary<<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">string</span>><span style="color: #000000;">(); </span><span style="color: #0000ff;">if</span> (strs.Length > <span style="color: #800080;">0</span>) <span style="color: #008000;">//</span><span style="color: #008000;">解析出請求路徑、post傳遞的參數(get方式傳遞參數直接從url中解析)</span>
{
if (strs.Contains("")) //包含空行 說明存在post數據
{
string post_data = strs[strs.Length - 1]; //最后一項
if (post_data != "")
{
string[] post_datas = post_data.Split('&');
foreach (string s in post_datas)
{
param.Add(s.Split('=')[0], s.Split('=')[1]);
}
}
}
}
return param;
}</span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">byte</span>[] pageHandle(<span style="color: #0000ff;">string</span><span style="color: #000000;"> pagePath) { </span><span style="color: #0000ff;">byte</span>[] pageContent = <span style="color: #0000ff;">null</span><span style="color: #000000;">; webRoot </span>= webRoot.TrimEnd(<span style="color: #800000;">'</span><span style="color: #800000;">/</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">\\</span><span style="color: #800000;">'</span><span style="color: #000000;">); pagePath </span>= pagePath.TrimEnd(<span style="color: #800000;">'</span><span style="color: #800000;">/</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">\\</span><span style="color: #800000;">'</span><span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (pagePath.Length==<span style="color: #800080;">0</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">foreach</span> (<span style="color: #0000ff;">string</span> page <span style="color: #0000ff;">in</span> defaultPage.Split(<span style="color: #800000;">'</span><span style="color: #800000;">,</span><span style="color: #800000;">'</span><span style="color: #000000;">)) { </span><span style="color: #0000ff;">if</span> (System.IO.File.Exists(webRoot +<span style="color: #000000;"> page)) { pagePath </span>=<span style="color: #000000;"> page; </span><span style="color: #0000ff;">break</span><span style="color: #000000;">; } } } </span><span style="color: #0000ff;">if</span> (System.IO.File.Exists(webRoot +<span style="color: #000000;"> pagePath)) pageContent </span>= System.IO.File.ReadAllBytes(webRoot +<span style="color: #000000;"> pagePath); </span><span style="color: #0000ff;">if</span> (pageContent == <span style="color: #0000ff;">null</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">string</span> content =<span style="color: #000000;"> notExistPage(); pageContent </span>=<span style="color: #000000;"> Encoding.UTF8.GetBytes(content); } </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pageContent; } </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> writeLog(<span style="color: #0000ff;">string</span><span style="color: #000000;"> msg) { Console.WriteLine(</span><span style="color: #800000;">"</span> <span style="color: #800000;">"</span> +<span style="color: #000000;"> msg); } </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> notExistPage() { </span><span style="color: #0000ff;">string</span> cont = <span style="color: #800000;">@"</span><span style="color: #800000;"><!DOCTYPE HTML>
<html>
<head> <link rel='stylesheet' type='text/css' href='NewErrorPageTemplate.css' > <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'> <title>This page can&rsquo;t be displayed</title> <script src='errorPageStrings.js' language='javascript' type='text/javascript'> </script> <script src='httpErrorPagesScripts.js' language='javascript' type='text/javascript'> </script> </head> <body onLoad='javascript:getInfo();'> <div id='contentContainer' class='mainContent'> <div id='mainTitle' class='title'>This page can&rsquo;t be displayed</div> <div class='taskSection' id='taskSection'> <ul id='cantDisplayTasks' class='tasks'> <li id='task1-1'>Make sure the web address <span id='webpage' class='webpageURL'></span>is correct.</li> <li id='task1-2'>Look for the page with your search engine.</li> <li id='task1-3'>Refresh the page in a few minutes.</li> </ul> <ul id='notConnectedTasks' class='tasks' style='display:none'> <li id='task2-1'>Check that all network cables are plugged in.</li> <li id='task2-2'>Verify that airplane mode is turned off.</li> <li id='task2-3'>Make sure your wireless switch is turned on.</li> <li id='task2-4'>See if you can connect to mobile broadband.</li> <li id='task2-5'>Restart your router.</li> </ul> </div> <div><button id='diagnose' class='diagnoseButton' onclick='javascript:diagnoseConnectionAndRefresh(); return false;'>Fix connection problems</button></div> </div> </body>
</html>";
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> cont; } }
}
這個web server的雛形就出來了,以后有需要的功能在慢慢往上添加吧
參考文章:
Socket網絡編程--簡單Web服務器各章節傳送門
Socket網絡編程--簡單Web服務器(1) http://www.cnblogs.com/wunaozai/p/3926033.html
Socket網絡編程--簡單Web服務器(2) http://www.cnblogs.com/wunaozai/p/3936295.html
Socket網絡編程--簡單Web服務器(3) http://www.cnblogs.com/wunaozai/p/3943952.html
Socket網絡編程--簡單Web服務器(4) http://www.cnblogs.com/wunaozai/p/3945218.html
Socket網絡編程--簡單Web服務器(5) http://www.cnblogs.com/wunaozai/p/3946486.html
Socket網絡編程--簡單Web服務器(6) http://www.cnblogs.com/wunaozai/p/3949324.html
源碼下載: http://files.cnblogs.com/wunaozai/WebServer.zip