1. 应用层
1.1 HTTP&HTTPS
1.1.1 HTTP
HTTP有两类报文:
(1)请求报文,从客户端项服务器发送请求报文。
(2)响应报文,从服务器到客户端的回答。
HTTP状态码:
1XX表示通知信息,如请求收到了或正在进行处理。
2XX表示成功。
3XX表示重定向,如要完成请求还必须采取进一步的行动。
4XX表示客户端的差错
5XX表示服务器的差错。
缺点:内容明文传输,没有经过任何加密,而这些明文数据会经过WiFi、路由器、运营商、机房等多个物理设备节点,如果在这中间任意一个节点被监听,传输的内容就会完全暴露,,这一攻击手法叫做MITM(Man In The Middle)中间人攻击。
1.1.2 HTTPS
a. 工作流程
- 用户在浏览器发起HTTPS请求(如 https://www.mogu.com/),默认使用服务端的443端口进行连接;
- HTTPS需要使用一套CA数字证书,证书内会附带一个公钥Pub,而与之对应的私钥Private保留在服务端不公开;
- 服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
- 客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
- 客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
- 服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
- 服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
- 客户端使用随机Key对称解密密文,得到HTTP数据明文;
后续HTTPS请求使用之前交换好的随机Key进行对称加解密。
b. 对称加密&非对称加密
对称加密是指有一个密钥,用它可以对一段明文加密,加密之后也只能用这个密钥来解密得到明文。如果通信双方都持有密钥,且天知地知你知我知,绝对不会有别的人知道,那么通信安全自然是可以得到保证的(在密钥足够强的情况下)。
非对称加密有两个密钥,一个是公钥,另一个是私钥。一般来说,公钥用来加密,这时密文只能用私钥才能解开。
参考文章1.2 键入网址发生的事情
解析URL地址
- 生成http请求消息
- DNS解析得到web服务器的ip地址
-
1.2.1 DNS
DNS的域名都是用句点来分隔的,比如www.server.com,这里的句点代表了不同层次之间的界限。
域名的层级关系类似于一个树状结构:- 根域名服务器
- 顶级域名服务器(com)
- 权限域名服务器(server.com)
- 本地域名服务器
1.2.1.1 域名解析的工作流程
- 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
- 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
- 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
- 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
- 顶级域名服务器说:“我给你负责 www.server.com 区域的权限 DNS 服务器的地址,你去问它应该能问到”。
- 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权限呢?就是我的域名我做主。
- 权限DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
- 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。
《计算机网络》课本中DNS解析流程:
下面简单讨论一下域名的解析过程。这里要注意两点。
第一,主机向本地域名服务器的查询一般都是采用递归查询(recursive query)。所请递归查询就是: 如果主机所询问的本地域名服务器不知道被查询域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其他根域名服务器继续发出查询请求报文(即替该主机继续查询),而不是让该主机自己进行下一步的查询。因此,递归查询返回的查询结果或者是所要查询的IP地址, 或者是报错,表示无法查询到所需的IP地址。
第二,本地域名服务器向根域名服务器的查询通常是采用迭代查询(iterative query)。选代查询的特点是这样的:当根域名服务器收到本地域名服务器发出的选代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地域名服务器:“你下一步应当向哪一个域名服务器进行查询”。 然后证让本地域名服务器进行后续的查询(而不是替本地域名服务器进行后续的查询)。 根域名服务器通常是把自己知道的项级域名服务器的IP地址告诉本地域名服条器,让本地域名服务器再同项级域名服务器查询。项级城名服务器在收到本地城名服务器的查询请求后,要么给出所要查询的IP地址,要么告诉本地域名服务器下一步应当向哪一个权限域名服务器进行查询,本地域名服务器就这样进行选代查询。最后,知道了所要解析的域名的IP地址, 然后把这个结果运回给发起查询的主机。当然,本地域名服务器也可以采用递归查询,这取决于最初的查询请求报文的设置是要求使用哪一种查询方式。
图6-5用例子说明了这两种查询的区别。
2. 运输层
运输层有一个很重要的功能就是——复用和分用B。“复用”是指在发送方不同的应用进程都可以使用同一个运输层协议传送数据,“分用”是指接收方的运输层在剥去报文的首部能够把这些数据正确交付目的应用进程。
网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信。
2.1 UDP
2.1.1 特点
- UDP是无连接的。即发送数据前不需要建立连接(也不需要释放连接),因此减少了开销和发送数据之前的时延。
- UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表
- UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一次报文。
- UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。
- UDP支持一对一、一对多、多对一和多对多的交互通信。
- UDP的首部开销小,只有8个字节,比TCP的20字节的首部要短。
2.1.2 首部格式
用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,由四个字段组成,每个字段的长度都是两个字节。
(1)源端口,源端口号。在选哟回信时选用。不需要时可用全0.
(2)目的端口,目的端口号。这在终点交付报文时必须使用。
(3)长度,UDP用户数据报的长度,其最小值是8(仅有首部)
(4)校验和,检测UDP用户数据报在传输中是否出错。有错就丢弃。
2.2 TCP
2.2.1 特点
- TCP是面向连接的运输层协议。
- 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。
- TCP提供可靠交付服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
- TCP提供全双工通信。TCP允许通信双方的应用程序在任何时候都能发送数据。
- 面向字节流。TCP中的“流”指的是流入到进程或从进程流出的字节序列。
2.2.2 TCP报文段的首部格式
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它首部各个字段的作用。
TCP报文首部的前20个字节是固定的,后面有4n字节是根据需要而增加的选项。因此TCP首部的最小长度是20字节。
首部固定部分各个字段的意义如下:
(1)源端口和目的端口,分别写入源端口号和目的端口号。
(2)序号。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要穿送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值指的是本报文所发送的数据的第一个字节的序号。
(3)确认号,是期望收到对方下一个报文的第一个数据字节的序号。若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。
(4)数据偏移,首部长度。指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。
(5)保留,保留为今后使用,但目前应置为0。
(6)紧急URG,当URG=1时,表明紧急指针字段有效。
(7)确认ACK,仅当ACK=1时确认号字段才有效。
(8)推送PSH
(9)复位RST,当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立运输连接。
(10)同步SYN,在建立连接时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使用SYN=1和ACK=1.因此SYN置为1就表示连接请求或连接接受报文。
(11)终止FIN,用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
(12)窗口,指的是发送本报文的一方的接收窗口。窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着。
(13)校验和,校验和字段检验的范围包括首部和数据两部分。
(14)紧急指针,仅在URG=1时才有意义,指出了紧急数据的末尾在报文中的位置。
(15)选项,长度可变。
(16)填充,为了使整个TCP首部长度是4字节的整数倍。
2.2.3 可靠传输的工作原理
a. 停止等待协议
”停止等待“就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
1.无差错情况
2.出现差错
3.确认丢失和确认迟到
b. 连续ARQ协议
2.2.4 TCP可靠传输的实现
a. 以字节为单位的滑动窗口
2.2.5 TCP的流量控制
流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
a. 利用滑动窗口实现流量控制
2.2.6 TCP的拥塞控制
拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。
TCP进行拥塞控制的算法有四种,即慢开始、拥塞避免、快重传和快恢复。
发送方维持一个叫拥塞窗口(cwnd)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。
慢开始:当主机开始发送数据时,由于不清楚网络的负载情况,所以如果立即把大量的数据字节注入到网络,那么就有可能引起网络发生拥塞。经验证明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说由小到大逐渐增大拥塞窗口数值。
拥塞避免算法的思路是让拥塞窗口cwnd缓慢地变大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd+1,而不是像慢开始阶段那样加倍增长。
采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。快重传算法首先要求接收方不要等待自己已发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
如图5-26所示,接收方收到了M和M2后都分别及时发出了确认。现假定接收方没有收到M3但却收到了M4。本来接收方可以什么都不做。但按照快重传算法,接收方必须立即发送对M2的重复确认,以便让发送方及早知道接收方没有收到报文段M3。发送方接着发送Ms和M6。接收方收到后也仍要再次分别发出对M2的重复确认。这样,发送方共收到了接收方的4个对M2的确认,其中后3个都是重复确认。快重传算法规定,发送方只要一连收到 3个重复确认,就知道接收方确实没有收到报文段M3, 因而应当立即进行重传(即“快重传”),这样就不会出现超时,发送方也不就会误认为出现了网络拥塞。使用快重传可以使整个网络的吞吐量提高约20%。
当TCP连接进行初始化时,把拥塞窗口cwnd设为1。慢开始门限的初始值设为16个报文段,及ssthresh=16。执行慢开始算法时,发送方每收到一个对新报文的确认ACK,就把拥塞窗口值加1,然后进行下一轮次的传输。因此拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时,就改为拥塞避免算法,拥塞窗口按线性规律增长。
当拥塞窗口cwnd=24时,网络出现了超时(图中点②),发送方判断为网络拥塞。于是调整门限值ssthresh=cwnd/2=12,同时设置拥塞窗口cwnd=1,进入慢开始阶段。
按照慢开始算法,发送方每收到一个对新报文的确认ACK,就把拥塞窗口值加1.当拥塞窗口cwnd=ssthresh=12时,改为执行拥塞避免算法,拥塞窗口按线性规律增大。
当拥塞窗口cwnd=16时,出现了一个新的情况,就是发送方一连收到3个对同一个报文的重复确认。发送方知道现在只是丢失了个别的报文段。于是不启动慢开始。而是执行快回复算法。这时,发送方调整门限值ssthresh=cwnd/2=8,同时设置拥塞窗口cwnd=ssthresh=8,并执行拥塞避免算法。
2.2.7 TCP的运输连接管理
a. TCP的连接建立
在TCP连接建立过程中要解决以下三个问题:
(1)要使每一方能够确知对方的存在。
(2)要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
(3)能够对运输实体资源进行分配。
TCP建立连接过程
A在打算建立TCP连接时,向B发出连接请求报文端,这时首部中的同步位SYN=1,同时选择一个初始序号seq=x。TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但要消耗掉一个序号。这时,TCP客户端进入SYN-SENT(同步已发送)状态。
B收到连接请求报文段后,如同意建立连接,则向A发送确认。在报文段中应把SYN位和ACK位都置为1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。请注意,这个报文段也不能携带数据,但同样要消耗一个序号。这时TCP服务器进程进入SYN=RECD(同步收到)状态。
TCP客户端进程收到B的确认后,还要向B给出确认。确认报文的ACK置1,确认号ack=y+1,而自己的序号seq=x+1。TCP的标准规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下,下一个数据报文段的序号仍是seq=x+1。这时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。
为什么 A 最后还要发送一次确认呢?
A 发出的第一个连接请求报文段并没有丢失,而是在某些网络节点长时间滞留了,以致延误到连接释放后的某个时间才到达 B。B 收到此失效的请求报文段后,就误认为 A 又发出一次新的连接请求。于是就向 A 发出确认报文段,同意建立连接,如果不采用报文握手,那 么只要 B 发送确认后,新的连接就建立了。由于现在 A 并没有发出建立连接请求,因此不会理睬 B 的确认,也不会向 B 发送数据。但 B却以为新的连接已经建立了,并一 直等待 A 发来数据。B 的许多资源就这样白白浪费了。
b. TCP的连接释放
(1)A把释放报文段首部的终止控制位FIN置为1,序号为seq=u,他等于前面已传送过的数据的最后一个字节的序号加1.(FIN-WAIT-1,消耗一个序号)
(2)B收到释放报文段后即发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。B进入CLOSE-WAIT状态。
A收到来自B的确认后,就进入FIN-WAIT-2状态,等待B发出的连接释放报文段。
(3)若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。这时B发出的连接释放报文段必须使FIN=1。先假定B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这时B就进入了LAST-ACK状态,等待A的确认。
(4)A在收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置1,确认号ack=w+1,而自己的序号是seq=u+1.然后进入TIME-WAIT状态。现在TCP连接还没有释放掉。必须经过时间等待计时器设置的时间ZMSL后,A才进入到CLOSED状态。时间MSL叫做最长报文段寿命。
为什么A在TIME-WAIT状态必须等待2MSL的时间呢?
第一,为了保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN + ACK报文段的确认。B会超时重传这个FIN + ACK报文段,而A就能在2MSL时间内收到这个重传的FIN+ ACK报文段。接着A重传一次确认,重新启动2MSL计时器。最后,A和B都正常进入到CLOSED状态。如果A在TIME-WAIT状态不等待一段时间, 而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN + ACK报文段,因而也不会再发送次确认报文段。这样,B就无法按照正常步骤进入CLOSED状态。<br /> 第二,防止上一节提到的“已失效的连接请求报文段"出现在本连接中。A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。B只要收到了A发出的确认,就进入CLOSED状态。同样,B在撤销相应的传输控制块TCB后,就结束了这次的TCP连接。我们注意到,B结束TCP连接的时间要比A旱些。