自定义web服务器(四)
关于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内容有大小限制。