TCP详解(一)

TCP

TCP报头/首部(header)

首部是四位长度,单位不是字节,而是4个字节。

image-20220726210305765

选项之前的20个字节是一定有的,首部最长是(1111 -> 15)也就是15 * 4 = 60字节。

选项部分范围就是0 ~ 40字节。

首部长度,其实就是划分了header和payload之前的分界线。

保留位:先占个位置,虽然暂时不用,保不齐以后可能会用。

关于TCP的特性

直观上看待TCP的特点

1.有连接

2.可靠传输

3.面向字节流

4.全双工

可靠性(TCP的核心特性)!!

尤其是要区分可靠性和安全性,TCP是可靠的,但是安不安全另当别论。

保证可靠性的核心:确认应答

1.确认应答(ACK)

发送方放松数据给接收方了,接收方就回应一个应答报文,如果发送方收到了这个应答报文,那么认为就是对方已经收到了。

由于网络上的传输,顺序是不确定的,因此就不能单纯的通过收到数据的顺序来确定逻辑,就需要对应大进行编号。

实际上,TCP传输数据不论条,而是论字节(面向字节流)

TCP的序号和确认序号,是以字节为单位进行编号的。

针对每个字节,分别编号,以此进行累加(实习上TCP的序列号的其实不一定是从1开始的)

确认序号和序列号之间的关系

image-20220727113927136

第一个请求,A给B发送了1000字节的数据,徐浩就是1-1000(假设从1就开始编号了),这个操作就相当于发了一个TCP数据报,这个数据报的序号是1,长度是1000.

确认应答数据报,里面的确认序号是1001,意思就是1001之前的数据,B已经收到了。

发送方就可以根据确认单应答报文来确定接收方是否是收到了,只要发送方搜狐当了应答,就认为解说房已经收到,可靠性传输就完成了。

TCP的核心是可靠性,可靠性的核心是确认应答。

2.超时重传

确认应答机制中,这个是比较顺利的情况,但是传输过程中还是可能出现丢包的。

一旦发生数据丢包,就要进入超时重传的机制中了。

实际场景中,比如发消息没收到回复。

此时存在两种可能:

1.发的消息过去了,但是丢了,对方没看见

2.我发的消息过去了,对方看见了,也恢复了,但是回复消息的时候丢了

发送方无法区分,当前是发的数据丢了,还是应答数据丢了。

发送方能做的事情,只是在一段时间之后,重新发送一条数据。

解决方案

发送方把数据发出去之后,等待500ms,若是没有收到应答,就认为是丢包了。

超时时间会动态变化,不是一成不变的。

不同场景等待时间不同,等待时间会逐渐延,延长时间也是意味着让数据重传的频率降低。重传还是失败,大概率传输是不通了。

3.连接管理(重点)

TCP是有连接的,连接管理说的就是,如何建立连接(三四握手),如何断开连接(四次挥手)。、

三次握手(建立连接)

举个生动形象的例子,比如我想向女神表白,为了表达我的爱慕之意,给女神写了一封情书,女神同意了。

image-20220727132145866

此时这个②过程表示两层含义,一层是接收到了我的爱慕表达,一层是也像我表达了爱慕之意

这样一来,男女朋友关系就建立了~

但是在TCP协议中实际的含义是如下这样:

image-20220727132800487

image-20220727132848564

谈谈三次握手的过程(画图)

image-20220727132911429

本质上,就是,A向B请求连接,B给与回应.B也向A请求连接,A也给与回应
本来应该是"四次握手"
但是中间两次操作,是可以合在一起的,这两个操作在时间上是同时发生的
当A的syn 到达B的时候,B的内核就会第一时间进行应答ACK,同时也会第一时间发起SYN.这两件事同时触发,于是就没必要分成两次传输,直接一步到位

为啥要三次握手,为啥要建立连接?

主要目的是有两个:

1.投石问路:通过三次握手的过程,来确认A和B之间的传输是通畅的。尤其是要确认,A和B各自的发送能力和接受能力是否正常。

2.协商参数,通过三次握手。让A和B之间通通气,选择一些传输中合适的参数,例如。TCP的序列号从几开始。

举个例子:想象打电话的过程

image-20220727133512842

延伸的问题:

为什么是三次握手不是四次握手。两次行不行?

image-20220727133717424

可以四次握手,但是完全没必要,中间的ACK和SYn是可以合并在一起的,如果分成两个,传输的开销要比第一个大,涉及到封装和分用,效率上略低一点。

image-20220727133908671

但是不能两次握手,这样不能知道A的接受能力和发送ACK是否正常,就相当于打电话A没有回应B,不知道是A的听筒坏了还是麦克风坏了。

TCP是有状态的

重点掌握的状态:

1.LISTEN:类似手机开机,信号满格,可以随时打入电话,服务器的状态。当我们创 建好ServerSocket实例的时候就进入了LISTEN状态。

2.ESTABLISHED:类似接通了电话,双方开始进行通话了,代码中accept返回了,得 到了一个clientSocket。

四次挥手(断开连接)

我们之前说三次握手,很明显我们知道A是客户端,B是服务器,客户端是主动的,服务器是被动的。

但是在四次挥手中,客户端和服务器都可以主动断开连接。

image-20220727145104469

FIN是结束报文段

针对上图中的ACK和FIN为啥不能合并?

对于 B 来说,ACK 和 FIN 的出发时机是不一样的。

1.B 只要搜狐到 FIN 就会立即触发 ACK ,这个是内核态完成的。

2.B 发送的FIN 实际是用户代码控制的,代码中出现了socket.close()这样的操作的时候,才会触发 FIN。甚至说,如果B的代码写的出问题了,有可能一直不调用close。

重要掌握的状态:

image-20220727144916876

CLOSE_WAIT:服务器搜狐到 FIN 之后,进入的状态,等待用户代码调用close,来发送 FIN。

TIME_WAIT:表示是客户端收到了FIN 之后进入了 TIME_WAIT,这个状态存在的一对主要就是为了处理最后一个ACK丢包问题。

在三次握手和四次挥手的过程中,同样可能会丢包,一旦丢包就会触发超时重传

1)第一个FIN丢了,A 迟迟收不到ACK,就会重传FIN

2)第一个ACK丢了,A迟迟收不到ACK,还会重传FIN

3)第二个FIN丢了,B 迟迟收不到ACK,还会重传FIN

4)第二个ACK丢了,B 迟迟收不到ACK,还会重传FIN

假设,如果A收到FIN之后,并返回ACK之后,连接就销毁,而不是进入TIME_WAIT状态,会发生什么?

此时一旦最后一个ACK丢了,就无法重传ACK了,因为连接已经销毁了。

TIME_WAIT即使进程已经退出了,TIME_WAIT状态仍然会存在(TCP 连接不会立即销毁)

TIME_WAIT会等待一定的时间,如果一定时间之内也没有重传的FIN过来,才真正销毁

如果服务器上出现大量的CLOSE_WAIT,这是啥情况?

这是代码出现的bug,close没有及时被调用到。

如果服务器上出现大量的TIME_WAIT,是啥情况?

这个也可能是代码bug,但是不能石锤,主动发起FIN的一方会进入TIME_WAIT,就需要排查服务器是否应该主动断开连接。

哪方先断开连接,哪方就会进入TIME_WAIT,进程退出之后,TIME_WAIT状态仍然存在,TCP连接仍然存在。

如果让服务器先退出,服务器这边就会进入到TIME_WAIT状态(原来的连接占据着端口),接下来如果服务器立即启动,新的进程又会尝试重新绑定这个端口。可能会存在端口绑定失败的情况。

4.滑动窗口

TCP不仅仅是为了保证可靠性,还要尽可能的提高传输效率。

其实可靠性和效率是矛盾的!TCP努力的在可靠性的前提之下,又做出了很多性能优化的手段。

image-20220727154242915

在这个过程中,发送方要花很多时间来等,这个等待就浪费了大量的时间。

image-20220727154413585

现在咱们是批量发送,一次发一波,一次等一波的ACK,把多组数据的ACK的等待时间给重叠起来了。

一次批量发的数据的长度,就成为“窗口大小”。

如果没有批量发送数据的长度限制(窗口无限大,完全不等ACK,就一直发),其实就没有可靠性可言。

如果窗口越大,整体的效率就越高,窗口越小,整体的效率就越低。

“滑动”的含义

image-20220727163409295

当前窗口范围是1001 - 5000 ,也就意味着,发送方现在同时发送了 1001 - 2000,2001 - 3000,3001 - 4000,4001 - 5000,同时等待着四组数据的ACK。

假设,2001这个ACK先到发送方就会知道了,1001 - 2000这个数据已经被对方收到了,发送方也就不用继续等待这个数据了,接下来就立即再发一个5001 - 6000,仍然保证窗口大小是4份数据,保证当前同时等待4份数据的ACK

并不是把4份ACK都等到才发新的数据,而是随着收到ACK就随着往后发送。

如果在滑动窗口的场景中出现了丢包,怎么办?

image-20220727163929753

这种情况下,没有关系,只要不是全部都丢了就好。

关键在于确认序列号的设定,后一个能包含前一个。

image-20220727164125055

这种情况下,仍然需要进行重传,但是如何让发送方知道是数据报丢了呢?

因为1001丢包了,主机B会一直索要1001,确认序列号仍然是1001。

发送方这边,如果连续几次看到1001这个ACK,就知道了1001这个数据丢失了,接下来就会重传1001。

前面的2001 - 7000,这些数据已经到达了接收端了,只不过是在接收缓冲区里等待,当1001 - 2000这个数据到打的时候,B就知道了,7001之前的数据都到齐了,此时继续索要7001这个数据即可。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

面向丈母娘编程@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值