zoukankan      html  css  js  c++  java
  • HTTP协议--MyWebServer

    HTTP协议

    HTTP协议是一种Web通信协议,通过特定的规则来实现服务器跟客户端的通信。HTTP协议有这样几个特点:

    (1)面向无连接的,一次只能处理一个请求,HTTP1.0服务器解析完客户端请求并作出应答后,会关闭连接;对于HTTP1.1应答后会等待一个非常短的时间,如果这段时间没有新请求,就会关闭连接。

    (2)HTTP协议是无状态的,即对处理过的事务没有记忆能力,它认为每一次请求都是陌生的独立的,为了解决这个问题,Web服务程序引进了cookie机制来维持请求状态。

    (3)HTTP协议允许传输任意类型的数据,对于正在传输的数据类型用Content-Type标记。

    URL

    url需要提供几种信息,一是采用的协议,二是连接的套接字,三是请求文件的路径,后面还可以跟上请求参数

    在浏览器中输入www.csdn.net,浏览器会自动帮我们转化为http://www.csdn.net/。

    采用的协议,这里已HTTP为例;连接套接字包括ip地址跟端口号,端口号一般都是默认的,不需要我们输入,ip地址我们一般输入域名,然后通过域名服务器解析;请求的路径,一般web程序会提供一个默认路径,如果不输,就是默认的;路径后面还可以跟上GET请求的参数,在请求路径后加上"?"参数之间用“&”连接。一般来说简单的无安全要求的数据,我们直接通过GET方法传递给服务器,而大量的隐私的数据我们通过Post方法传递给服务器。

    HTTP请求报文

    请求报文分为三个部分,请求行、请求头、请求体,格式都是固定的。如图1.1所示:

    请求的方法如下:

    (1)GET   请求获取url标识的资源

    (2)POST  请求获取url标识的资源并像浏览器传递数据

    (3)HEAD  请求服务器对url的响应报头

    (4)PUT  请求服务器存储资源,并以url作为其标识

    (5)DELETE 请求服务器删除url标识的资源

    (6)TRACE  请求服务器返回发送过去的请求,主要用于诊断和测试

    HTTP响应报文

    响应报文也分为三个部分,响应行、响应头、响应体,如图1.2所示:

    响应行包含了协议版本,状态码,和状态码的描述。

    状态码是一个百位数,100段表示请求已接受,继续处理;200段表示请求成功;300段表示请求需要做进一步处理,比如说跳转;400段表示请求错误,并且是客户端的原因;500段表示服务器的原因导致了请求错误。

    常见的响应码如下:

    200 : OK

    302 : Found 重定向

    400 : Bad Request 错误请求,发出错误的不符合Http协议的请求

    401 : Unauthorized  请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用

    403 : Forbidden 禁止

    404 : Not Found 未找到

    500 : Internal Server Error 服务器内部错误

    503 : Service Unavailable  一般是访问人数过多

    常用的类型名:

    Server 提供web服务器版本信息;Content-Type 响应的内容的类型 ;Content-Length 响应体的字节长度  ;Connetion 连接的方式信息 ;Accept-Ranges 接收数据的方式,通常是字节数组。

    MyWebServer

    复习,模拟一个自己的简单服务器程序,步骤如下:

    1、接收浏览器发送的请求(socket)
    2、分析请求报文(http),请求的路径
    3、生成响应报文,响应体
    4、发送响应内容

    //用的winform,首先搭建一个窗体,点击开始后开始监听。

    [csharp] view plain copy
     
    1. namespace MyWebServer  
    2. {  
    3.     public partial class Form1 : Form  
    4.     {  
    5.         public Form1()  
    6.         {  
    7.             InitializeComponent();  
    8.             Control.CheckForIllegalCrossThreadCalls = false;  
    9.         }  
    10.         void ShowMsg(string str)  
    11.         {  
    12.             txtLog.AppendText(str+" ");  
    13.         }  
    14.         private void btnStart_Click(object sender, EventArgs e)  
    15.         {  
    16.             //点击开始运行,创建一个socket对象并进行监听  
    17.             IPAddress ip;int p;  
    18.             if (!IPAddress.TryParse(txtIp.Text, out ip))  
    19.             {  
    20.                 MessageBox.Show("请输入一个正确的ip地址");  
    21.                 return;  
    22.             }  
    23.             if(!int.TryParse(txtPort.Text,out p))  
    24.             {  
    25.                 MessageBox.Show("请输入一个正确的端口号");  
    26.                 return ;  
    27.             }  
    28.             IPEndPoint point = new IPEndPoint(ip, p);  
    29.             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
    30.             try  
    31.             {  
    32.                 socket.Bind(point);//绑定地址  
    33.                 socket.Listen(10);//开始监听  
    34.                 ShowMsg("开始运行。。。");  
    35.                 //创建一个后台线程接受客户端的连接  
    36.                 Thread th = new Thread(Listen);  
    37.                 th.IsBackground = true;  
    38.                 th.Start(socket);  
    39.             }  
    40.             catch (Exception ex)  
    41.             {  
    42.                 MessageBox.Show(ex.Message);  
    43.             }  
    44.         }  
    45.         private void Listen(object o)  
    46.         {  
    47.             Socket socket = o as Socket;  
    48.             while (true)  
    49.             {  
    50.                 Socket connSocket = socket.Accept();//通信用的socket  
    51.                 ShowMsg(connSocket.RemoteEndPoint + "连接成功");  
    52.                 //创建一个DataConnection类专门接收请求和发送响应  
    53.                 DataConnection dc = new DataConnection(connSocket, ShowMsg);  
    54.                   
    55.             }  
    56.         }  
    57.     }  
    58. }  

    其中接收和发送请求交给DataConnection

    [csharp] view plain copy
     
    1. namespace MyWebServer  
    2. {  
    3.     delegate void DelHandler(string str);//用于传递方法ShowMsg  
    4.     class DataConnection  
    5.     {  
    6.         Socket connsocket; DelHandler del; string request;  
    7.         public DataConnection(Socket socket,DelHandler del)  
    8.         {  
    9.             connsocket=socket;  
    10.             this.del = del;  
    11.             request = RecRequest();  
    12.             del(request);//通过委托调用窗体的ShowMsg方法,显示请求报文  
    13.             //分析请求报文,放在Request类中进行  
    14.             Request req = new Request(request);  
    15.             staticPage(req.Url);  
    16.         }  
    17.         //处理静态页面,根据请求的路径来判断  
    18.         void staticPage(string url)  
    19.         {  
    20.             string extension = Path.GetExtension(url).TrimStart('.');//获取后缀名  
    21.             switch (extension)  
    22.             {  
    23.                 case "html":  
    24.                 case "htm":  
    25.                 case "css":  
    26.                 case "js":  
    27.                 case "jpg":  
    28.                 case "png":  
    29.                 case "gif":  
    30.                     //处理静态页面,生产响应有Response类负责  
    31.                     ProcessStaticPage(url);  
    32.                     break;  
    33.                 case"she":  
    34.                     //处理动态页面  
    35.   
    36.                     break;  
    37.                 default:  
    38.                     break;  
    39.             }  
    40.         }  
    41.         //处理静态页面  
    42.         void ProcessStaticPage(string url)  
    43.         {   
    44.             //求出绝对路径  
    45.             string path = AppDomain.CurrentDomain.BaseDirectory + url;  
    46.             //判断文件是否存在  
    47.             if (File.Exists(path))  
    48.             {  
    49.                 using (FileStream fs=new FileStream(path,FileMode.Open))  
    50.                 {  
    51.                     //读取文件  
    52.                     byte[]buffer=new byte[fs.Length];  
    53.                     fs.Read(buffer, 0, buffer.Length);  
    54.                     //生成响应头,交给Response类  
    55.                     Response response = new Response(200, buffer.Length, url);  
    56.                     connsocket.Send(response.GetResponseHeads());  
    57.                     connsocket.Send(buffer);  
    58.   
    59.                     connsocket.Close();  
    60.                     del("关闭了连接");  
    61.                 }  
    62.             }  
    63.             else  
    64.             {  
    65.                 //文件不存在,404页面  
    66.                             }  
    67.         }  
    68.         void ProcessDTPage(string url)  
    69.         {  
    70.             string fileName = Path.GetFileNameWithoutExtension(url);//一般把文件名定义成类名  
    71.             //获取当前方法所在的命名空间  
    72.             string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;  
    73.             //类的全名称  
    74.             string fullName = nameSpace + "." + fileName;  
    75.             IHttpHandler handler = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;  
    76.             if (handler != null)  
    77.             {  
    78.                 //响应体  
    79.                 byte[] buffer = handler.ProcessRequest();  
    80.                 //响应头  
    81.                 Response res = new Response(200, buffer.Length, url);  
    82.   
    83.                 //发送  
    84.                 connsocket.Send(res.GetResponseHeads());  
    85.                 connsocket.Send(buffer);  
    86.                 connsocket.Close();  
    87.                 del("关闭连接");  
    88.             }  
    89.         }  
    90.         //接收请求报文  
    91.         string RecRequest()  
    92.         {  
    93.             byte[] buffer = new byte[1024 * 1024];  
    94.             int num=connsocket.Receive(buffer);  
    95.             return Encoding.UTF8.GetString(buffer,0,num);  
    96.   
    97.         }  
    98.   
    99.     }  
    100. }  

    分割请求信息得到路径和准备响应头都交给对应的类做了:

    [csharp] view plain copy
     
    1. class Request  
    2. {  
    3.     string request; public string Url;  
    4.     public Request(string request)  
    5.     {  
    6.   
    7.         try  
    8.         {  
    9.             string[] strs = request.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);  
    10.             string first = strs[0];  
    11.             string[] requstHeads = first.Split( ' ');  
    12.             Url = requstHeads[1];//请求行中的路径  
    13.         }  
    14.         catch (Exception ex)  
    15.         {  
    16.             Url = "";  
    17.         }  
    18.     }  
    19. }  
    [csharp] view plain copy
     
    1. class Response  
    2. {  
    3.     Dictionary<int, string> dic = new Dictionary<int, string>();//存状态码根描述  
    4.     int stateCode = 200;  
    5.     int contentLength;  
    6.     string contentType;  
    7.     public Response(int stateCode,int contentLength,string url)  
    8.     {  
    9.         Fill();  
    10.         this.stateCode = stateCode;  
    11.         this.contentLength = contentLength;  
    12.         GetContentType(url);  
    13.     }  
    14.     //生成响应头  
    15.     public byte[] GetResponseHeads()  
    16.     {  
    17.         StringBuilder sb = new StringBuilder();  
    18.         sb.AppendLine("HTTP/1.1 "+stateCode+" "+dic[stateCode]);  
    19.         sb.AppendLine("Content-Length: " + contentLength);  
    20.         sb.AppendLine("Content-Type: "+ contentType +";charset=utf-8 ");  
    21.         return Encoding.UTF8.GetBytes(sb.ToString());  
    22.     }  
    23.     //根据后缀给contenttype赋值  
    24.     void GetContentType(string url)  
    25.     {  
    26.         //.htm  
    27.         string ext = Path.GetExtension(url);  
    28.         switch (ext)  
    29.         {  
    30.             case ".htm":  
    31.             case ".html":  
    32.                 contentType = "text/html";  
    33.                 break;  
    34.             case ".css":  
    35.                 contentType = "text/css";  
    36.                 break;  
    37.             case ".js":  
    38.                 contentType = "text/javascript";  
    39.                 break;  
    40.             case ".jpg":  
    41.                 contentType = "image/jpeg";  
    42.                 break;  
    43.             default:  
    44.                 contentType = "text/html";  
    45.                 break;  
    46.         }  
    47.     }  
    48.     void Fill()  
    49.     {  
    50.         dic.Add(200, "OK");  
    51.         dic.Add(400, "Not Found");  
    52.     }  
    53. }  
     
  • 相关阅读:
    思科交换机端口安全配置
    华为交换机端口安全配置
    多行文本出现省略号必备的条件(面试题)
    单行文本出现省略号必备的条件(面试题)
    让多个元素在一行显示的方法和技巧(面试题)
    overflow的多个作用
    雪碧图的使用和制作技巧
    列举background属性的8个属性值(面试题)
    background-origin设置背景图像的参考原点(位置)
    background-clip设置对象的背景图像向外裁剪的区域
  • 原文地址:https://www.cnblogs.com/lancidie/p/8477156.html
Copyright © 2011-2022 走看看