關於HTTP協議的具體內容,前面章節已經有所講解,相信讀者已有所瞭解,在此不在累述,本章節講解自定義web伺服器。
一,.net提供自定義Web伺服器的類
以下只是寫主要的類
1.HTTPListener:對TCPListener的封裝
2.TCPListener:對Socket的封裝
3.Socket:對協議棧傳輸層介面的封裝
二,用.net提供的類進行web伺服器的自定義
1.用HTTPListener
using System; using System.Net; using System.IO; using System.Text; using System.Globalization; using System.Threading; namespace Microsoft.Samples.HttpListener { static class HttpRequestListener { public static void Main() { string[] prefixes = new string[1]; prefixes[0] = "http://localhost:8080/"; ProcessRequests(prefixes); } private static void ProcessRequests(string[] prefixes) { if (!System.Net.HttpListener.IsSupported) { Console.WriteLine( "Windows XP SP2, Server 2003, or higher is required to " + "use the HttpListener class."); return; } // URI prefixes are required, if (prefixes == null || prefixes.Length == 0) throw new ArgumentException("prefixes"); // Create a listener and add the prefixes. System.Net.HttpListener listener = new System.Net.HttpListener(); Thread handleRequest = null; foreach (string s in prefixes) { listener.Prefixes.Add(s); } try { // 啟動監聽,開始監聽請求 listener.Start(); Console.WriteLine("Listening..."); while(true) { HttpListenerResponse response = null; // GetContext 在等待一個請求時將阻塞 . HttpListenerContext context = listener.GetContext(); handleRequest = new Thread(delegate() { try { Console.WriteLine("當前執行緒是否為執行緒池執行緒:" + (Thread.CurrentThread.IsThreadPoolThread==true?"是":"否")); Console.WriteLine("當前執行緒總數:" + System.Diagnostics.Process.GetCurrentProcess().Threads.Count.ToString()); response = context.Response; string responseBody = "<HTML><head><script language='javascript' type='text/javascript'>function test(){alert('你好');}</script></head><BODY><form>The time is currently " + DateTime.Now.ToString() + "<br/>"; responseBody += "<input type='button' value='js測試' id='test1' onclick='test();'/><br/><input type='submit' value='提交測試' id='test2' /></form></BODY></HTML>"; string responseHeader = string.Format( "Content-Type: text/html; charset=UTf-8;Content-Length: {0}", responseBody.Length); byte[] responseBodyBytes = Encoding.UTF8.GetBytes(responseBody); response.ContentLength64 = responseBodyBytes.Length; System.IO.Stream output = response.OutputStream; // 向客戶端傳送迴應頭資訊 response.Headers.Add(responseHeader); // 向客戶端傳送狀態行 response.StatusCode = (int)HttpStatusCode.OK; response.ProtocolVersion = Version.Parse("1.1"); // 想客戶端傳送主體部分 output.Write(responseBodyBytes, 0, responseBodyBytes.Length); } catch (HttpListenerException ex) { Console.WriteLine(ex.Message); } finally { if (response != null) response.Close(); } Thread.Sleep(100000); }); handleRequest.Start(); } } catch (HttpListenerException ex) { Console.WriteLine(ex.Message); } finally { //停止監聽 listener.Close(); Console.WriteLine("Done Listening."); } } } }
服務端執行效果:
客戶端執行效果:
2.用TCPListener
private static void ProcessRequestsWithTcpListener() { TcpListener server=new TcpListener(IPAddress.Any,8081); server.Start(); Console.WriteLine("HTTP Server Start Listening...."); while (true) { TcpClient client = server.AcceptTcpClient(); Thread handleRequest = new Thread(delegate() { try { NetworkStream inputoutputstream = client.GetStream(); Byte[] buffer = new Byte[1024]; int readLength = inputoutputstream.Read(buffer, 0, buffer.Length); String inputoutputstring = Encoding.ASCII.GetString(buffer, 0, readLength); Console.WriteLine("客戶端資訊:" + client.Client.RemoteEndPoint); Console.WriteLine("客戶端請求資訊:\n" + inputoutputstring); String statusLine = "HTTP/1.1 200 OK\r\n"; string responseBody = "<HTML><head><script language='javascript' type='text/javascript'>function test(){alert('你好');}</script></head><BODY><form>The time is currently " + DateTime.Now.ToString() + "<br/>"; responseBody += "<input type='button' value='js測試' id='test1' onclick='test();'/><br/><input type='submit' value='提交測試' id='test2' /></form></BODY></HTML>"; string responseHeader = string.Format( "Content-Type: text/html; charset=UTf-8\r\nContent-Length: {0}\r\n", responseBody.Length + statusLine.Length); byte[] responseStatusLineBytes = Encoding.UTF8.GetBytes(statusLine); byte[] responseHeaderBytes = Encoding.UTF8.GetBytes(responseHeader); byte[] responseBodyBytes = Encoding.UTF8.GetBytes(responseBody); // 寫入狀態行資訊 inputoutputstream.Write(responseStatusLineBytes, 0, responseStatusLineBytes.Length); // 寫入迴應的頭部 inputoutputstream.Write(responseHeaderBytes, 0, responseHeaderBytes.Length); // 寫入迴應頭部和內容之間的空行 inputoutputstream.Write(new byte[] { 13, 10 }, 0, 2); // 寫入迴應的內容 inputoutputstream.Write(responseBodyBytes, 0, responseBodyBytes.Length); } catch (Exception ex) { Console.WriteLine("異常資訊:"+ex.Message); } finally { // 關閉與客戶端的連線 client.Close(); } }); handleRequest.Start(); } }
服務端執行效果:
客戶端執行效果:和1類似
3.用Socket
private static void ProcessRequestsWithSocket() { Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); server.Bind(new IPEndPoint(IPAddress.Any, 8082)); server.Listen(100); Console.WriteLine("HTTP Server Start Listening...."); while (true) { Socket client = server.Accept(); Thread handleRequest = new Thread(delegate() { try { Byte[] buffer = new Byte[1024]; int readLength = client.Receive(buffer, buffer.Length,SocketFlags.None); String inputoutputstring = Encoding.ASCII.GetString(buffer, 0, readLength); Console.WriteLine("客戶端資訊:" + client.RemoteEndPoint); Console.WriteLine("客戶端請求資訊:\n" + inputoutputstring); String statusLine = "HTTP/1.1 200 OK\r\n"; string responseBody = "<HTML><head><script language='javascript' type='text/javascript'>function test(){alert('你好');}</script></head><BODY><form>The time is currently " + DateTime.Now.ToString() + "<br/>"; responseBody += "<input type='button' value='js測試' id='test1' onclick='test();'/><br/><input type='submit' value='提交測試' id='test2' /></form></BODY></HTML>"; string responseHeader = string.Format( "Content-Type: text/html; charset=UTf-8\r\nContent-Length: {0}\r\n", responseBody.Length + statusLine.Length); byte[] responseStatusLineBytes = Encoding.UTF8.GetBytes(statusLine); byte[] responseHeaderBytes = Encoding.UTF8.GetBytes(responseHeader); byte[] responseBodyBytes = Encoding.UTF8.GetBytes(responseBody); // 寫入狀態行資訊 client.Send(responseStatusLineBytes); // 寫入迴應的頭部 client.Send(responseHeaderBytes); // 寫入迴應頭部和內容之間的空行 client.Send(new byte[] { 13, 10 }); // 寫入迴應的內容 client.Send(responseBodyBytes); } catch (Exception ex) { Console.WriteLine("異常資訊:" + ex.Message); } finally { // 關閉與客戶端的連線 client.Close(); } }); handleRequest.Start(); } }
服務端和客戶端執行效果和2類似.
宣告:2和3程式碼修改自:http://www.cnblogs.com/zhili/archive/2012/08/23/WebServer.html 只為交流,不為商用.
備註:面試時,常問的一個問題是:http中post和get請求的區別
個人感覺:1.兩者傳輸方式不同,post將資料放在請求內容裡傳輸,get放在請求行傳輸
2.post內容沒有大小限制,get內容有大小限制。