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,首先搭建一个窗体,点击开始后开始监听。

  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+"\r\n");
  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. }

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

  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. break;
  36. default:
  37. break;
  38. }
  39. }
  40. //处理静态页面
  41. void ProcessStaticPage(string url)
  42. {
  43. //求出绝对路径
  44. string path = AppDomain.CurrentDomain.BaseDirectory + url;
  45. //判断文件是否存在
  46. if (File.Exists(path))
  47. {
  48. using (FileStream fs=new FileStream(path,FileMode.Open))
  49. {
  50. //读取文件
  51. byte[]buffer=new byte[fs.Length];
  52. fs.Read(buffer, 0, buffer.Length);
  53. //生成响应头,交给Response类
  54. Response response = new Response(200, buffer.Length, url);
  55. connsocket.Send(response.GetResponseHeads());
  56. connsocket.Send(buffer);
  57. connsocket.Close();
  58. del("关闭了连接");
  59. }
  60. }
  61. else
  62. {
  63. //文件不存在,404页面
  64. }
  65. }
  66. void ProcessDTPage(string url)
  67. {
  68. string fileName = Path.GetFileNameWithoutExtension(url);//一般把文件名定义成类名
  69. //获取当前方法所在的命名空间
  70. string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
  71. //类的全名称
  72. string fullName = nameSpace + "." + fileName;
  73. IHttpHandler handler = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;
  74. if (handler != null)
  75. {
  76. //响应体
  77. byte[] buffer = handler.ProcessRequest();
  78. //响应头
  79. Response res = new Response(200, buffer.Length, url);
  80. //发送
  81. connsocket.Send(res.GetResponseHeads());
  82. connsocket.Send(buffer);
  83. connsocket.Close();
  84. del("关闭连接");
  85. }
  86. }
  87. //接收请求报文
  88. string RecRequest()
  89. {
  90. byte[] buffer = new byte[1024 * 1024];
  91. int num=connsocket.Receive(buffer);
  92. return Encoding.UTF8.GetString(buffer,0,num);
  93. }
  94. }
  95. }

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

  1. class Request
  2. {
  3. string request; public string Url;
  4. public Request(string request)
  5. {
  6. try
  7. {
  8. string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
  9. string first = strs[0];
  10. string[] requstHeads = first.Split( ' ');
  11. Url = requstHeads[1];//请求行中的路径
  12. }
  13. catch (Exception ex)
  14. {
  15. Url = "";
  16. }
  17. }
  18. }
  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\r\n");
  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的更多相关文章

  1. HTTP协议系列(1)

    一.为什么学习Http协议       首先明白我们为什么学习HTTP协议,也就是说明白HTTP协议的作用.HTTP协议是用于客户端与服务器之间的通讯.明白了HTTP协议的作用也就知道了为什么要学习H ...

  2. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

  3. 协议森林17 我和你的悄悄话 (SSL/TLS协议)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. TLS名为传输层安全协议(Transport Layer Protocol),这个协议是一套加密的 ...

  4. 协议森林16 小美的桌号(DHCP协议)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. DHCP协议用于动态的配置电脑的网络相关参数,如主机的IP地址,路由器出口地址.DNS域名服务器地 ...

  5. 简约之美Jodd-http--深入源码理解http协议

    Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架.简单,却很强大! jodd-http是一个轻巧的HTTP客户端.现在我们以一个简单的示例从源码层看看是如何实现的? Http ...

  6. 【JavaScript】javascript中伪协议(javascript:)使用探讨

    javascript:这个特殊的协议类型声明了URL的主体是任意的javascript代码,它由javascript的解释器运行. 比如下面这个死链接: <a href="javasc ...

  7. SNMP简单网络管理协议

    声明:以下内容是学习谌玺老师视频整理出来(http://edu.51cto.com/course/course_id-861.html) SNMP(Simple Network Management ...

  8. 海鑫智圣:物联网漫谈之MQTT协议

    什么是MQTT协议 MQTT(消息队列遥测传输协议)是IBM在1999年专门针对物联网等应用场景来制订的轻量级双向消息传输协议,它主要是为了解决物联网上使用到的设备的互相通信的问题,以及这些设备与后端 ...

  9. linux-图形化远程管理协议

    远程管理控制方式: RDP(remote desktop protocol)协议: telnet: SSH(Secure Shell): RFB(Remote FrameBuffer)协议(图形化远程 ...

随机推荐

  1. Sqlserver在现有数据库中插入数据

    需求:1.客户提供的excel表和数据库中的表结构总是有一些差距,id的生成,各种字段的关联等等 2. 如何在Excel中生成Guid. 1.在Excel的宏中执行以下代码: Private Decl ...

  2. 在k8s集群中,利用prometheus的jmx_exporter进行tomcat的JVM性能监控,并用grafana作前端展示

    查找了很多文档,没有完全达到我要求的, 于是,作了一定的调整,成现在这样. 操作步骤如下: 一,准备好两个文件. jmx_prometheus_javaagent-0.3.1.jar jmx_expo ...

  3. Git(二)使用git管理文件版本(TortoiseGit )

    一.创建版本库 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都 ...

  4. php实现https(tls/ssl)双向认证

    php实现https(tls/ssl)双向认证 通常情况下,在部署https的时候,是基于ssl单向认证的,也就是说只要客户端认证服务器,而服务器不需要认证客户端. 但在一些安全性较高的场景,如银行, ...

  5. 【LOJ】#6434. 「PKUSC2018」主斗地

    题解 什么,我这题竟然快到了LOJ rk1???? 搜起来有点麻烦,不过感觉还是比斗地主好下手(至今没敢写斗地主 首先是暴力搜牌型,最多\(3^{16}\)(什么判解还要复杂度怂成一团)的样子?? 然 ...

  6. date命令使用文档

    date命令的帮助信息 [root@localhost source]# date --help用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] ...

  7. PHP函数之trigger_error

    在程序开发中,如果我们编码不规范,比如调用不存在的变量.语法错误.少了个逗号,这些都会引起系统报错并进行提示,但是今天,突然发现PHP还有这样一个函数,用于自动触发一个报错提示,并且会将报错信息写入p ...

  8. 访问url下载文件----python

    工作上有时候有需求,会下载pdf,doc,zip等文件,可以用以下方法,推荐使用第一种 下载文件: import urllib import urllib2 import requests url = ...

  9. centos7 firewall 相关

    1.centos 6 是iptables, 7 开始就以firewalld代替iptables; 2.systemctl stop firewalld.service  停 systemctl sta ...

  10. springmvc配置MappingJackson2HttpMessageConverter实现属性驼峰和下划线的转换

    需求 php调用java接口时,因为php那边的属性都是下划线风格,java这边的属性都是驼峰的风格.配置springmvc的json转换,在requestBody的时候(调用对象的set 方法)将j ...