HTTP协议--MyWebServer

摘要:
HTTP协议HTTP协议是一种Web通信协议,通过特定的规则实现服务器和客户端之间的通信。HTTP协议是无状态的,也就是说,它没有处理事务的内存能力。它认为,每个请求都是陌生和独立的。为了解决这个问题,Web服务程序引入了cookie机制来维护请求状态。HTTP协议允许传输任何类型的数据,传输的数据类型标记为内容类型。[csharp]viewplaincopynamespaceMyWebServer{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();Control.CheckForIllegalCrossThreadCalls=false;}voidShowMsg{txtLog.AppendText;}privatevoidbtStart_单击{//单击“开始”运行,创建套接字对象并侦听IPAddressip;intp;if(!
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所示:

HTTP协议--MyWebServer第1张

请求的方法如下:

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

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

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

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

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

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

HTTP响应报文

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

HTTP协议--MyWebServer第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. }  
 

免责声明:文章转载自《HTTP协议--MyWebServer》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇(转)高性能JavaScript:加载和运行(动态加载JS代码)欧几里得距离下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Spring 远程调用工具类RestTemplateUtils

Spring 远程调用Rest服务工具类,包含Get、Post、Put、Delete四种调用方式。 依赖jar <dependency> <groupId>org.springframework</groupId> <artifactId>s...

WAF功能介绍(入门扫盲篇)

本文转自:https://mp.weixin.qq.com/s/CXTedk3BAVNt0elOsaFccA 做了略微的修改。 1 WAF功能 WAF全称叫Web Application Firewall,和传统防火墙的区别是,它是工作在应用层的防火墙,主要对web请求/响应进行防护。那么WAF有什么功能呢? 防火墙都是防御性的产品,有防就有攻,要了解WA...

【Python】爬取百度图片

所需要导入的包:BeautifulSoup:该模块用于接收一个HTML或XML字符串,然后将其进行格式化,之后遍可以使用他提供的方法进行快速查找指定元素,从而使得在HTML或XML中查找指定元素变得简单。这里是用来获取一个页面里面的各个标签及里面的内容,我们主要用到它里面的find(),find_All()函数requests:是用来获取网页信息的,也就是...

ionic2中使用自定义图标

在ionic2中使用自定义图标,如iconfont(阿里巴巴矢量图标)。 先在http://www.iconfont.cn/ 中找到自己需要的图标,然后将图标加入购物车,然后下载该图标。 下载完成后解压,打开文件demo_unicode.html可以看到它提供的使用方法,我们在ionic2中按照以下方法使用: 1、在项目的assets目录下新建fonts...

Base64和urlencode

https://www.jianshu.com/p/b611e220ef2d Base64 使用base64的初衷。是为了方便把含有不可见字符串的信息用可见字符串表示出来 我们知道在计算机中任何数据都是按ascii码存储的,而ascii码的128~255之间的值是不可见字符。 而在网络上交换数据时,比如说从A地传到B地,往往要经过多个路由设备,由于不同的...

Asp.net Web.Config 配置元素customErrors

Asp.net配置文件的配置方式,其实在MSDN里面是写得最清楚的了。可惜之前一直未曾了解到MSDN的强大。 先贴个地址:http://msdn.microsoft.com/zh-cn/library/dayb112d(v=vs.80).aspx,然后逐个分析。我希望自己能够从头到尾认真学完这系列东西。为了不至于让自己太早放弃,我决定从自己用过的配置文件学...