01 Web 世界中的 TCP/IP 是如何工作的

408 阅读8分钟

衡量web页面性能的一个重要标准:FP (页面从加载到首次开始绘制的时长)

如何优化网页加载速度来缩小FP呢?这就需要你对TCP/IP有充分的了解,因为无论是HTTP还是WebSocket,它们都是建立在TCP/IP的基础上的。

在网络中,一个文件通常会被拆分为很多数据包来进行传输,而数据包在传输过程中又有很大概率丢失或者出错。那么如何保证页面文件能被完整地送达浏览器呢?

1. IP

数据包要在互联网上进行传输,就要符合网际协议(Internet Protocol,简称IP)标准。

想把数据包从A传输到B,在传输之前,数据包会被附加上主机B和主机A的地址信息,这样是为了能够在传输过程中正确寻址和主机B返回消息给主机A。这些附加的信息被装在一个叫做IP头的数据结构里,IP头包含IP版本、源IP地址、目标IP地址、生存时间等信息。

把网络简单分为三层结构:

1-1.png

2. UDP

IP是非常底层的协议,只负责把数据包传送到对方主机,但是对方主机却不知道传递给哪个程序,因此,需要基于IP之上开发的能和应用打交道的协议。最常见的是UDP(用户数据报协议 User Datagram Protocol)

UDP中很重要的一个信息就是端口号,主机上的程序想要访问网络必须绑定一个端口号,通过端口号UDP就能把指定的数据包传递给主机上对应的程序。

所以,IP通过IP地址将数据包发送到相应的主机,UDP再派发给主机上不同的端口对应的应用程序。

把三层结构扩充为四层:

1-2.png

  • UDP缺点:

    1. 不保证数据的可靠性,传输过程中虽然可以校验数据包,但还是可能会有各种因素导致数据包出错,对于出错的数据包,UDP没有重传机制,UDP发送数据包之后也不确定是否能够到达对应主机。

    2. 数据包不完整,大文件在传输的时候会被拆解为很多的小数据包进行传输,这些小的数据包所经历的路由和到达的时间不同,在到达接受端时,UDP不知道如何组装来还原为完整的文件

  • UDP优点:不需要建立连接,传输速度非常快。 应用在一些关注速度、但不那么严格要求数据完整性的领域,如在线视频、互动游戏等。

UDP通信模型:

1-3.jpg

3. TCP

基于UDP传输的的不可靠性和组装问题,引入了TCP(Transmission Control Protocol,传输控制协议)。

TCP是一种面向有连接的、可靠的、基于字节流的传输层通信协议。

对比UDP,它有如下特点:

  • 面向连接,三次握手之后才进行传输
  • 对于数据包丢失,TCP提供了超时重传机制
  • 有序传输,TCP引入了数据包排序机制,保证大文件传输到对应主机之后能够按序组装或者舍弃重复的数据包,保证数据传输无差错。
  • 阻塞/流量控制,避免主机发送得过快⽽使接收⽅来不及完全收下

包含TCP的传输过程:

1-4.png

TCP头除了像UDP头一样包含目标端口和主机端口之外,还包含用于排序的序列号

不同于UDP,TCP是面向有连接的。需要经过创建连接、数据传送、终⽌连接三个步骤:

1-5.png

3.1 TCP的三次握手

1-6.png

(1)第⼀次握⼿:Client将标志位SYN置为1,随机产⽣⼀个值seq=J,并将该数据包发送给Server, Client进⼊SYN_SENT状态,等待Server确认。

(2)第⼆次握⼿:Server收到数据包后由标志位SYN=1知道Client请求建⽴连接,Server将标志位 SYN和ACK都置为1,ack=J+1,随机产⽣⼀个值seq=K,并将该数据包发送给Client以确认连接请 求,Server进⼊SYN_RCVD状态。

(3)第三次握⼿:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK 置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确 则连接建⽴成功,Client和Server进⼊ESTABLISHED状态,完成三次握⼿,随后Client与Server之间可以开始传输数据了。

3.2 TCP的四次挥手

1-7.png (1) 第⼀次挥⼿:主机1(可以是客户端,也可以是服务器端),设置 Sequence Number 和 Acknowledgment Number ,向主机2发送⼀个 FIN 报⽂段;此时,主机1进 ⼊ FIN_WAIT_1 状态;这表示主机1没有数据要发送给主机2了;

(2) 第⼆次挥⼿:主机2收到了主机1发送的 FIN 报⽂段,向主机1回⼀个 ACK 报⽂段, Acknowledgment Number 为 Sequence Number 加1;主机1进⼊ FIN_WAIT_2 状态;主机2告诉主机1,我也没有数据要 发送了,可以进⾏关闭连接了;

(3) 第三次挥⼿:主机2向主机1发送 FIN 报⽂段,请求关闭连接,同时主机2进⼊ CLOSE_WAIT 状态;

(4) 第四次挥⼿:主机1收到主机2发送的 FIN 报⽂段,向主机2发送 ACK 报⽂段,然后主机1进 ⼊ TIME_WAIT 状态;主机2收到主机1的 ACK 报⽂段以后,就关闭连接;此时,主机1等待2MSL后依 然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

TCP连接总过程模型:

1-5.jpg

4. 问题汇总

  1. 为什么需要三次握⼿,两次不可以吗?或者四次、五次可以吗?

    我们来分析⼀种特殊情况,假设客户端请求建⽴连接,发给服务器SYN包等待服务器确认, 服务器收到确认后,如果是两次握⼿,假设服务器给客户端在第⼆次握⼿时发送数据,数据从服 务器发出,服务器认为连接已经建⽴,但在发送数据的过程中数据丢失,客户端认为连接没有建 ⽴,会进⾏重传。假设每次发送的数据⼀直在丢失,客户端⼀直SYN,服务器就会产⽣多个⽆效 连接,占⽤资源,这个时候服务器可能会挂掉。这个现象就是我们听过的“SYN的洪⽔攻击”。

    总结:第三次握⼿是为了防⽌:如果客户端迟迟没有收到服务器返回确认报⽂,这时会放弃 连接,重新启动⼀条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连 接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。

  2. 为什么TIME_WAIT状态需要经过2MSL(最⼤报⽂段⽣存时间)才能返回到CLOSE状态?

    ⾸先,MSL即Maximum Segment Lifetime,就是最⼤报⽂⽣存时间,是任何报⽂在⽹络上 的存在的最⻓时间,超过这个时间报⽂将被丢弃。《TCP/IP详解》中是这样描述的:MSL是任何 报⽂段被丢弃前在⽹络内的最⻓时间。RFC 793中规定MSL为2分钟,实际应⽤中常⽤的是30 秒、1分钟、2分钟等。

    TCP的TIME_WAIT需要等待2MSL,当TCP的⼀端发起主动关闭,三次挥⼿完成后发送第四次挥⼿的ACK包后就进⼊这个状态,等待2MSL时间主要⽬的是:防⽌最后⼀个ACK包对⽅没有 收到,那么对⽅在超时后将重发第三次握⼿的FIN包,主动关闭端接到重发的FIN包后可以再发⼀ 个ACK应答包。在TIME_WAIT状态时两端的端⼝不能使⽤,要等到2MSL时间结束才可以继续使 ⽤。当连接处于2MSL等待阶段时任何迟到的报⽂段都将被丢弃。

  1. client发送完最后⼀个ack之后,进⼊time_wait状态,但是他怎么知道server有没有收到这个ack呢? 莫⾮sever也要等待⼀段时间,如果收到了这个ack就close,如果没有收到就再发⼀个fin给client?这么 说server最后也有⼀个time_wait?

    因为⽹络原因,主动关闭的⼀⽅发送的这个ACK包很可能延迟,从⽽触发被动连接⼀⽅重传 FIN包。极端情况下,这⼀去⼀回,就是两倍的MSL时⻓。如果主动关闭的⼀⽅跳过TIME_WAIT 直接进⼊CLOSED,或者在TIME_WAIT停留的时⻓不⾜两倍的MSL,那么当被动关闭的⼀⽅早先发出的延迟包到达后,就可能出现类似下⾯的问题:1.旧的TCP连接已经不存在了,系统此时 只能返回RST包2.新的TCP连接被建⽴起来了,延迟包可能⼲扰新的连接,这就是为什么 time_wait需要等待2MSL时⻓的原因。

  1. 为什么连接的时候是三次握⼿,关闭的时候却是四次握⼿?

    因为当Server端收到Client端的SYN连接请求报⽂后,可以直接发送SYN+ACK报⽂。其中 ACK报⽂是⽤来应答的,SYN报⽂是⽤来同步的。但是关闭连接时,当Server端收到FIN报⽂ 时,很可能并不会⽴即关闭SOCKET,所以只能先回复⼀个ACK报⽂,告诉Client端,"你发的 FIN报⽂我收到了"。只有等到我Server端所有的报⽂都发送完了,我才能发送FIN报⽂,因此不 能⼀起发送。故需要四步握⼿。

想了解更多内容,请查看02 HTTP的请求流程 - 掘金 (juejin.cn)