十一8天玩的有点嗨了,好不容易闲下来,整理下http协议这个似懂非懂的东西。本篇文章为个人看书,阅读博客所得,如有任何问题,欢迎指出。学习计算机网络全凭个人爱好,一些,改配置参数调优之类的就没有深入,后续用到在学。
HTTP协议–超文本传输协议(Hypertext Transfer Protocol),HTTP协议是建立在TCP协议之上的一种应用,好本篇结束😄。开个玩笑,就单纯根据字面意思翻译一下。
超文本:文字、图片、音频和视频等的混合体传输:A->B A传输到B(过程我不管,我只管结果。🐶)协议:大于一个人的约定没啥词还能拆了,把这三个词整合下就是http协议:这下面是我个人的翻译
http协议:在计算机之间用来传输文字、图片、音频和视频等的混合体的一种约定。HTTP协议呢经历过几个版本:http/0.9,http/1.0,http/1.1,http/2,http/3。(了解下就行了)
http/0.9 根据蒂姆·伯纳斯·李最初的论文来的,只能传输纯文本http/1.0 确立了个大纲,并不是特别标准http/1.1 目前在使用的最广泛的协议,功能相对而言比较宽泛http/2.0 Google的SPDY协议,兼容1.1的同时对速度进行了改进,还没广泛用呢,Google公司就提出了3.0http/3.0 在http/3.0中,将弃用TCP协议,改为使用基于UDP协议的QUIC协议实现。(谷歌挺爱内斗啊)http/1.1 的新特性主要有
增加了 PUT、DELETE 等新的方法。增加了缓存管理和控制。支持长链接。允许响应数据分块(chunked),利于传输大文件。请求/响应头都支持host。URL和URIwiki百科里面解释是可以把他们理解成一个,URL是URI子集。 wiki百科连接 URI URL
URL的两个例子
scheme:协议类型(http://表示http协议,类似的还有ftp,file等): // :层级URL标记符号,人家就这么规定的user information:访问资源需要的凭证信息(可省略)host:port:主机名(或者是域名)加端口号,默认端口号可以省略path: 标记资源所在位?query: 查询条件,?为起点,k=v格式,多个条件用&连接,中文日文转成%utf-8fragment:片段首先判断你输入的是一个合法的 URL 还是一个待搜索的关键词,并且根据你输入的内容进行自动完成、字符编码等操作。
HSTS由于安全隐患,会使用 HSTS 强制客户端使用 HTTPS 访问页面。详见:你所不知道的 HSTS。
其他操作浏览器还会进行一些额外的操作,比如安全检查、访问限制(之前国产浏览器限制 996.icu)。
检查缓存整体结构如下
请求头和响应头第一行不同
请求头:方法 URI http版本 响应头: http版本 状态码 响应短语常用请求头
这里只列出了常用的,不常用的详见 Request Headers
协议头说明示例Accept浏览器可以接受服务器回发的类型Accept: text/htmlAccept-Encoding浏览器申明自己接收的编码方法Accept-Encoding: gzip, deflateAccept-Language浏览器申明自己接收的语言Accept-Language:zh-CN,zh;q=0.9Connection是否支持长链接Connection: keep-aliveHost请求报头域Host: www.baidu.comReferer告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。Referer:https://www.baidu.com/?tn=62095104_8_oem_dgUser-Agent客户端使用的操作系统和浏览器的名称和版本user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36Cache-Control缓存Cache-Control:max-age=10Cookie服务器和客户端预定的一些必要信息cookie: _ga=GA1.2.1083213790.1598628058; 常用响应头只整理了常用响应头,实际的还有很多,详细请见 Response Headers
协议头说明示例Cache-Control缓存Cache-Control:max-age=10Content-Type资源文件的类型,还有字符编码Content-Type:text/html;charset=UTF-8Content-Encoding编码格式Content-Encoding:gzipDate服务端发送资源时的服务器时间Date: Tue, 03 Apr 2018 03:52:28 GMTServer服务器和相对应的版本Server: BWS/1.1Transfer-Encoding服务器发送的资源的方式是分块发送的Transfer-Encoding: chunkedConnection是否支持长链接Connection: keep-aliveExpires缓存过期时间,还是以Cache-Control为准Expires: Sun, 25 Oct 2020 06:13:15 GMTAccess-Control-Allow-Origin指定哪些网站可以跨域资源共享,*是所有网站都可以Access-Control-Allow-Origin: www.baidu.com响应信息里面状态码
1xx:告知请求的处理进度和情况2xx:成功 200 OK204 No Content 无返回内容 3xx:重定向 301 Moved Permanently 资源已经被搬到其他地方,新URI在响应头的Location里面302 Found 零时重定向,也是在Location里面303 See Other 和302差不多,但是只能用GET请求 4xx:客户端错误 401 Unauthorized 认证失败403 Forbidden 请求资源的访问被服务器拒绝了404 Not Found 表示服务器找不到你请求的资源405 Not Allowed 请求方法错误 5xx:服务器错误 500 Internal Server Error 服务器内部错误503 Service Unavailable 服务器超负载或正停机维护,无法处理请求小tips 一个url只能获取一个资源,比如一个页面内包含很多的图片,js啥的。他只能不停的发送请求,你以为只敲了一下回车,其实发送了很多次的请求
生成了请求信息后,还不知道IP地址,DNS查询把域名转换成端口号。这个过程类似知道了饭馆的名字还不知道具体地址。
先发送给本地DNS服务器,询问IP地址本地DNS服务器在缓存中找到了,直接返回IP地址,没有找到就去DNS根服务器中请求DNS根服务器根据域名 www.163.com 从后向前解析,让服务器去 com域服务器找本地DNS服务器就再向com域服务器问。com域服务器让本地服务器再去163域服务器找。本地DNS服务器再向163域服务器发送请求。163域服务器找到后把IP地址返回。本地DNS服务器再讲IP地址返回域名的层级关系大致如下 实际情况中一般一台DNS服务器管理多个域,而且每次这么从上倒下查询压力会特别大,为了缓解这些压力,会使用缓存,有缓存记录的直接返回,直接中缓存的位置乡下查询。
PS:如果你改了hosts文件,上面一切就不会发生了,直接访问你host指定的IP地址,你瞎写基本上就直接找不到了。
有了消息体有了对方的IP地址,下面就开始发送消息了。 发送消息的大致顺序是:
创建套接字与服务器套接字连接发送数据断开并删除套接字操作系统中大致关系如下,上面的部分会向下面委派工作。相当于java的各种api,最顶层的浏览器不需要关心底层是啥样的,只要调用Socket库就行了。上面的DNS查询也是Socket里面的一个功能。
套接字(Socket)是啥? 在计算机科学中是电脑网络中进程间资料流的端点(来自于wiki百科)。一个笼统概念,一个存放通信对象的IP地址,端口号,通信操作等各种控制信息的内存空间,创建了套接字(Socket)以后就可以使用各种api。它是通信的一段,一般通信客服端和服务端各有一个。netstat可以显示套接字内容 创建套接字 应用程序申请创建套接字,协议栈就会在内存中开辟出这么一块内存空间出来,此时收发数据还没有开始,此时内存中还只有一些初始状态的信息。与服务器套接字连接 创建完套接字之后,就会调用Socket库中的connect,随后会把服务器的IP地址和端口号等信息写入。服务器呢一般启动就会创建套接字等带客户端的连接,但是双方都互相不知道通信对象是谁,这样干等下去就永远无法通信,客户端就会主动和服务器通信(所以http请求都是客户端发起的,服务器只做响应)。连接完成后呢双方的套接字互相知晓对方的套接字。这个过程就是三次握手,下面会进行讲解,这里先了解下大体情况即可。发送数据 应用程序调用Socket中的write进行发送,但不是立马发送会先缓存在发送的缓冲区中。每次发多少由程序定,可能一次发送全部,也可能分批次发送。MTU(最大输出但愿一般为1500字节,包含头的总长度),MTU-请求头=MSS(最大分段大小,TCP头+IP头一般是40字节)。MSS一般是在建立连接的时候就已经双方确定过。 如果缓存区中的数据超过MSS,就会以MSS为单位拆分,每一块加上请求头进行发送。分包发送后,服务器会进行确认,把收到的序号+收到的数据长度发送给客户端,客户端进行确认,发现有问题,就会进行重发,一个IP分片丢失,也会引起重传的。此时服务器还没有响应,应用程序会暂时挂起等待服务器响应。服务器返回数据就是重复上面的过程,这里就不赘述了。断开并删除套接字 此时已经该发的数据已经都发完了,就没必要继续连接了。此时客户端和服务器端都可以发起断开请求。以服务器发送断开请求为例,会调用Socket库的close方法,协议栈会发送FIN为1的TCP头部,客户端会发送ACK号。等数据全部接收到了客户端也会调用Socket库的close方法,和上面一样客户端会发送FIN为1的TCP包,服务器会发送ACK号,至此通信就结束了。等到接收到确认的ACK号(如果没有收到可能会重传)就会删除套接字。这个过程就是四次握手,后面会讲。上面讲了生成包,还只是很小的一部分。当开始发送消息时,Socket库向下调用TCP模块,此时会给请求加上TCP头部。 TCP模块委托给IP模块的时候会添加IP头和MAC头部 后续就会交给网卡,网卡会将数字信号转化为光信号,通过网线发送给集线器路由器等设备,最终会传到对方的网卡中,对方网卡转化为主席信号,通过IP模块把IP头和MAC头去掉,通过TCP模块再把TCP头给去掉,最后得到原始请求信息。 下面就是大概的整体流程了
有了对方的IP地址表示了要传输的目的地,只是知道了要发给谁。但是以太网不知道这个东西,只知道MAC地址。MAC地址是生产网卡时候,写在ROM里面的,而IP地址是英特网给电脑的一个编号,这个有点类似于住宅地址和身份证号码。 此时就有问题了,不知道对方的mac地址。IP模块会根据目标IP地址区路由表中的Gateway那一列查出发送给哪个路由器,获取到路由器的IP地址,知道了IP地址不知道MAC地址咋办,通过ARP协议群发消息,如果有人发现IP地址是自己的会把MAC地址也给返回了。
MAC地址会填这个MAC地址。接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。在网络包传输的过程中,源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址。
单个请求过程你应该了解了,如果每一次都要3次握手4次挥手这个连接和销毁的过程就耗费了特别长的时间,所以出现了长链接。请求头中Connection是keep-alive就代表是长连接
三次握手是由客户端先发起。
客户端会初始化序号,把序列号写进TCP头部的序列号中,并把SYN设置为1,此后客户端会进入SYS_SENT状态。服务器收到客户端的SYN报文后,也会初始化自己的序列号,写进TCP头部的序列号中,并把服务端发送过来的序列号+1写进确认序号中。然后把SYN和ACK标识位设置成1并返回,并进入SYN_RCVD状态。客户端收到后把服务器发过来的序号+1写进确认序号中,把ACK标识位设置成1。进入ESTABLISHED状态。这次发送可以携带数据。服务器收到后也进入ESTABLISHED状态。四次挥手双方都可以发起请求。
某一方打算关闭连接会发送一个TCP头部FIN标示为1的报文,随后进入FIN_WAIT_1状态对方收到后先发送ACK应答报文,进入CLOSED_WAIT状态己方收到后进入FIN_WAIT_2的状态对方等处理完后发送FIN的报文,进入LAST_ACK状态己方收到后,发送ACK应答报文,进入TIME_WAIT状态对方收到应答报文后进入CLOSE状态己方在进过2MSL后也进入CLOSE状态参考博客 小林coding图解网络 参考书籍 《图解HTTP》 《图解TCP/IP》 《网络是怎样连接的》