www.cnblogs.com/jin-zhe/p/1...
大致流程
- 1、URL 解析
- 2、DNS 查询
- 3、TCP 连接
- 4、请求和传输数据
- 浏览器渲染页面
一、解析URL
URL(Universal Resource Locator):统一资源定位符。俗称网页地址或者网址。
URL用来表示某个资源的地址。(通过俗称就能看出来)
URL主要由以下几个部分组成:
· a.传输协议(引导向http、https、ftp)
· b.服务器
· c.域名
· d.端口
· e.虚拟目录
· f.文件名
· g.锚
· h.参数
现在来讨论URL解析,当在浏览器中输入URL后,浏览器首先对拿到的URL进行识别,抽取出域名字段。
二、DNS解析
DNS解析(域名解析),DNS实际上是一个域名和IP对应的数据库。
IP地址往都难以记住,但机器间互相只认IP地址,于是人们发明了域名,让域名与IP地址之间一一对应,它们之间的转换工作称为域名解析,域名解析需要由专门的域名解析服务器来完成,整个过程是自动进行的。
可以在浏览器中输入IP地址浏览网站,也可以输入域名查询网站,虽然得出的内容是一样的,但是调用的过程不一样,输入IP地址是直接从主机上调用内容,输入域名是通过域名解析服务器指向对应的主机的IP地址,再从主机调用网站的内容。
在进行DNS解析时,会经历以下步骤:
1. 查询浏览器缓存(浏览器会缓存之前拿到的DNS 2-30分钟时间),如果没有找到,那么->
2. 检查系统缓存,检查hosts文件,这个文件保存了一些以前访问过的网站的域名和IP的数据。它就像是一个本地的数据库。如果找到就可以直接获取目标主机的IP地址了。没有找到的话,那么->
3. 检查路由器缓存,路由器有自己的DNS缓存,可能就包括了这在查询的内容;如果没有,那么->
4. 查询ISP DNS 缓存: ISP服务商DNS缓存(本地服务器缓存)那里可能有相关的内容,如果还不行的话,那么->
5. 递归查询 :从根域名服务器到顶级域名服务器再到极限域名服务器依次搜索对应目标域名的IP。
通过以上的查找,就可以获取到域名对应的IP了。接下来就是向该IP地址定位的HTTP服务器发起TCP连接。
三、浏览器与网站建立TCP连接(三次握手)
三握手四挥手
第一次握手:客户端向服务器端发送请求(SYN=1) 等待服务器确认;
第二次握手:服务器收到请求并确认,回复一个指令(SYN=1,ACK=1);
第三次握手:客户端收到服务器的回复指令并返回确认(ACK=1)。
所以三次握手目的是保证双方都有发送和接收的能力。
通过三次握手,建立了客户端和服务器之间的连接,现在可以请求和传输数据了。
四、请求和传输数据
比如要通过get请求访问"www.dydh.org/",通过抓包可以看到:
请求网址(url):www.dydh.org/
请求方法:GET
远程地址:IP
状态码:200 OK
Http版本: HTTP/1.1
请求头: ...
响应头: ...
服务器发现当前请求无cookie
响应头中有一个:Set-Cookie:"PHPSESSID=c882giens9f7d3oglcakhrl994; path=/" ,说明浏览器中没有关于这个网站的cookie信息。
当我们下一次访问相同的网站时:
可以看到,请求头中包含了这个cookie信息,
Cookie:"PHPSESSID=c882giens9f7d3oglcakhrl994; CNZZDATA1253283365=1870471808-1473694656-%7C1473694656"
cookie可以用来保存一些有用的信息:Cookies如果是首次访问,会提示服务器建立用户缓存信息,如果不是,可以利用Cookies对应键值,找到相应缓存,缓存里面存放着用户名,密码和一些用户设置项。
通过这种GET请求,和服务器的响应。可以将服务器上的目标文件传输到浏览器进行渲染。
五、浏览器渲染页面
客户端拿到服务器端传输来的文件,找到HTML和MIME文件,通过MIME文件,浏览器知道要用页面渲染引擎来处理HTML文件。
MIME类型
text/plain
text/html
image/jpeg
image/png
audio/mpeg
audio/ogg
audio/*
video/mp4
application/*
application/json
application/javascript
application/ecmascript
application/octet-stream
1. 浏览器会解析html源码,然后创建一个 DOM树。
在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文本节点。
2. 浏览器解析CSS代码,计算出最终的样式数据,形成css对象模型CSSOM。
首先会忽略非法的CSS代码,之后按照浏览器默认设置------用户设置------外联样式------内联样式------HTML中的style样式顺序进行渲染。
3. 利用DOM和CSSOM构建一个渲染树(rendering tree)。
渲染树和DOM树有点像,但是是有区别的。
DOM树完全和html标签一一对应,但是渲染树会忽略掉不需要渲染的元素,比如head、display:none的元素等。
而且一大段文本中的每一个行在渲染树中都是独立的一个节点。
渲染树中的每一个节点都存储有对应的css属性。
4. 浏览器就根据渲染树直接把页面绘制到屏幕上。
备注
4次挥手
1221= 客户端发、服务端发、服务端发、客户端发
1)客户端进程发出连接释放报文 ,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT (关闭等待)状态 。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受 。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间 。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
- 3次握手是为了解决,让服务器和客户端知道自己具备接收和发送的能力 如果两次那服务端只能知道自己能接受成功
- 4次挥手是因为服务端在接受关闭请求时 可能存在数据未传输完毕的情况,所以需要先告知客户端已收到关闭请求,然后等发送完毕再告知客户端可以关闭了
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
【问题3】为什么不能用两次握手进行连接?
答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
【问题5】为什么需要第四次挥手
收到客户端发来的FIN报,服务端会立刻回答主动方,让客户端进入FIN-WAIT-1状态。防止客户端重复的发FIN报。
四次挥手的本质原因是申请断开时请求数据未发完,主动让浏览器关闭连接
第二次第三次很有必要 在客服端第1次挥手时,服务端可能还在发送数据。
所以第2次挥手和第3次挥手不能合并。
第四次需要客户端回复确认 ,服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
为什么客户端发完ACK后不立刻CLOSED?如果ACK丢失了,服务端会重发FIN,而客户端CLOSED已经无法接收了,那么服务端就会永远无法正常关闭。服务器关闭后,浏览器发送第四次成功后就会close
UDP
首先 UDP 协议是面向无连接的,也就是说不需要在正式传递数据之前先连接起双方。然后 UDP 协议只是数据报文的搬运工,不保证有序且不丢失的传递到对端,并且UDP 协议也没有任何控制流量的算法,总的来说 UDP 相较于 TCP 更加的轻便。
面向无连接
首先 UDP 是不需要和 TCP 一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。
并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
具体来说就是:
- 在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
- 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
不可靠性
首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。
并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。
再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。
高效
虽然 UDP 协议不是那么的可靠,但是正是因为它不是那么的可靠,所以也就没有 TCP 那么复杂了,需要保证数据不丢失且有序到达。
因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的。
UDP 头部包含了以下几个数据
- 两个十六位的端口号,分别为源端口(可选字段)和目标端口
- 整个数据报文的长度
- 整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误
传输方式
UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。
适合使用的场景
UDP 虽然对比 TCP 有很多缺点,但是正是因为这些缺点造就了它高效的特性,在很多实时性要求高的地方都可以看到 UDP 的身影。
直播
想必大家都看过直播吧,大家可以考虑下如果直播使用了基于 TCP 的协议会发生什么事情?
TCP 会严格控制传输的正确性,一旦有某一个数据对端没有收到,就会停止下来直到对端收到这个数据。这种问题在网络条件不错的情况下可能并不会发生什么事情,但是在网络情况差的时候就会变成画面卡住,然后再继续播放下一帧的情况。
但是对于直播来说,用户肯定关注的是最新的画面,而不是因为网络条件差而丢失的老旧画面,所以 TCP 在这种情况下无用武之地,只会降低用户体验。
王者荣耀
虽然我具体不知道王者荣耀底层使用了什么协议,但是对于这类实时性要求很高的游戏来说,UDP 是跑不了的。
为什么这样说呢?首先对于王者荣耀来说,用户体量是相当大的,如果使用 TCP 连接的话,就可能会出现服务器不够用的情况,因为每台服务器可供支撑的 TCP 连接数量是有限制的。
再者,因为 TCP 会严格控制传输的正确性,如果因为用户网络条件不好就造成页面卡顿然后再传输旧的游戏画面是肯定不能接受的,毕竟对于这类实时性要求很高的游戏来说,最新的游戏画面才是最需要的,而不是老旧的画面,否则角色都不知道死多少次了。
- UDP 相比 TCP 简单的多,不需要建立连接,不需要验证数据报文,不需要流量控制,只会把想发的数据报文一股脑的丢给对端
- 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
TCP
TCP 基本是和 UDP 反着来,建立连接断开连接都需要先需要进行握手。在传输数据的过程中,通过各种算法保证数据的可靠性,当然带来的问题就是相比 UDP 来说不那么的高效。
TCP 是全双工的,在断开连接时两端都需要发送 FIN 和 ACK。
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
2. 总结
-
TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
-
虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
-
对数据准确性要求高,速度可以相对较慢的,可以选用TCP
-
建立连接需要三次握手,断开连接需要四次握手
-
滑动窗口解决了数据的丢包、顺序不对和流量控制问题
-
拥塞窗口实现了对流量的控制,保证在全天候环境下最优的传递数据
判断 ip 地址是哪类( A类,B类,C类这种
A类地址:由1字节(每个字节是8位)的网络地址和3个字节主机地址组成
B类地址:由2个字节的网络地址和2个字节的主机地址组成
C类地址:由3个字节的网络地址和1个字节的主机地址组成