TCP详解

TCP

TCP连接管理

TCP 协议只运行在 end systems上,因此中间的网络元素(比如:routers 和 link-layer switches)并不会去维护 TCP 的连接状态。事实上,中间的 routers 完全不知道有 TCP 连接,它们只看 datagrams. 一个 TCP 连接提供 full-duplex service,假设一个 host 上的进程 A 与 另一个 host 上的进程 B 之间存在一个 TCP 连接,那么应用层数据在从进程 A 到进程 B 的同时,也可以从进程 B 到进程 A.一旦 TCP 连接建立完成以后,2个进程之间就可以彼此发送数据。如下图所示,进程写一个数据流通过 Socket,然后 TCP 把这些数据放到 TCP send buffer(它在 three-way handshake 期间被设置) 中,不时 TCP 会从这个 buffer 中取一些数据,接着把它们传递到网络层
在这里插入图片描述

TCP三次握手

1、client-side TCP 首先发送一个特殊的 TCP segment 到 server-side TCP. 这个特殊的 TCP segment 并不包含任何应用层的数据,但是这个 segment header 中的 SYN bit 被设为1,因此,这个 segment 叫做 SYN segment. 另外, client 也会随机选择一个初始的 sequence number (client_isn),并把它放到 segment 中的 sequence number field. 接着这个 segment 被封装到一个 ==IP datagram ==中,发给 server.

2、一旦 server 端收到了步骤1中发送的 SYN segment,它会分配针对这个连接的 buffers 和变量,之后发送一个 connection-granted segment 给 client TCP,这个 segment 也不包含任何的应用层数据,但是这个 segment 有3个 header 会被设置:(1)SYN bit 设为1. (2)acknowledgment field 设置为 client_isn+1. (3)server 会选择一个属于它自己的初始 sequence number (server_isn),并把它放到 sequence number field. 这个 connection-granted segment 被称作 SYNACK segment

3、根据收到的 SYNACK segment,client 会分配针对这个连接的 buffers 和 变量。然后,client 会向 server 发送一个 segment,这个 segment acknowledges server 的 connection-granted segment(通过把 server_isn+1 放入到 acknowledgment field 中),由于连接已经建立,SYN bit 会设置成 0,这个 segment 也有可能会携带 client-to-server 的数据

在这里插入图片描述
面试题:为什么进行三次握手而不是两次(正解)?
https://www.cnblogs.com/zmlctt/p/3690998.html
我们知道,3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
(1)现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁
(2)主 要是为了防止已失效的连接请求报文段突然又传到了B,因而产生错误。假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络结 点长时间滞留了,一直延迟到连接释放以后的某个时间才到达B,本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次 新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了,这样一直等待A发来数据,B的许多 资源就这样白白浪费了。

TCP四次挥手

一个 TCP 连接中的 2 个进程中的任何一个进程都可以结束连接,当一个连接结束时,2个 host 中的资源buffers 和 variables被释放。现在我假设是 client 想要关闭连接,它的整个过程如下图:
在这里插入图片描述
(1)客户端A发送一个FIN=1,序列号,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK=1,确认序号为收到的序号加1)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN=1给客户端A(报文段6)。
(4)客户端A发回ACK=1报文确认,并将确认序号设置为收到序号加1。
面试题:为什么建立连接要三次握手而关闭连接是四次挥手。
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的
面试题: 为什么为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
(1)可靠的实现TCP全双工链接的终止。
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文
(2)允许老的重复的分节在网络中消逝。
假 设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在 相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连 接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。 通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。
面试题 TCP协议和UDP协议的区别是什么
(1)TCP协议是面向连接的,有连接的意思是开始传输实际数据之前TCP的客户端和服务器端必须通过三次握手建立连接,会话结束之后也要结束连接。而UDP是无连接的
(2)TCP协议保证可靠,数据按序发送,按序到达,提供超时重传来保证可靠性,但是UDP不保证按序到达,甚至不保证到达,只是努力交付,即便是按序发送的序列,也不保证按序送到。
(3)TCP协议所需资源多,TCP首部需20个字节(不算可选项),UDP首部字段只需8个字节。
TCP有流量控制和拥塞控制,UDP没有,网络拥堵不会影响发送端的发送速率
(4)TCP是一对一的连接,而UDP则可以支持一对一,多对多,一对多的通信。
(5)TCP面向的是字节流的服务,UDP面向的是报文的服务。
面试题: 四次挥手释放连接时,等待2MSL的意义?
(1)第 一,为了保证A发送的最有一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN和ACK 报文段的确认。B会超时重传这个FIN和ACK报文段,而A就能在2MSL时间内收到这个重传的ACK+FIN报文段。接着A重传一次确认。
(3)第二,就是防止上面提到的已失效的连接请求报文段出现在本连接中,A在发送完最有一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。

TCP保证可靠性的方式

TCP协议保证数据传输可靠性的方式主要有:
校验和
序列号
确认应答
超时重传
连接管理
流量控制
拥塞控制
转自:https://blog.csdn.net/liuchenxia8/article/details/80428157
TCP协议保证数据传输可靠性的方式主要有:

序列号与确认应答

序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号。
确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发

超时重传

在进行TCP传输时,由于确认应答与序列号机制,也就是说发送方发送一部分数据后,都会等待接收方发送的ACK报文,并解析ACK报文,判断数据是否传输成功。如果发送方发送完数据后,迟迟没有等到接收方的ACK报文,这该怎么办呢?而没有收到ACK报文的原因可能是什么呢?

首先,发送方没有介绍到响应的ACK报文原因可能有两点:

(1)数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到
(2)接收方接收到了响应的数据,但是发送的ACK报文响应却由于网络原因丢包了
TCP在解决这个问题的时候引入了一个新的机制,叫做超时重传机制。简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行ACK应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送ACK应答。

连接管理

连接管理就是三次握手与四次挥手的过程,在前面详细讲过这个过程,这里不再赘述。保证可靠的连接,是保证可靠性的前提。

流量控制

接收端在接收到数据后,对其进行处理。如果发送端的发送速度太快,导致接收端的结束缓冲区很快的填充满了。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,超时重传呀什么的。而TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制
在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。

拥塞控制

理解了 sender 如何控制发送速率,如何感知网络是否拥堵,现在让我们考虑一下 TCP 是如何操作它们,从而做到 congestion control 的。如果理解了上面所有的内容,那么你就可以很容易理解这个算法,其实整个算法所描述的就是在3个状态slow start,congestion avoidance,和 fast recovery
首先我们谈谈 slow start 这个状态的重点内容:

1、从上图中的初始状态中我们可以看出,cwnd 的初始值为 1,每当 new ACK(sender 此时会认为网络状况很好) 事件触发时,sender 会让 cwnd = cwnd + MSS,因此在这个状态小,虽然初始的发送速率很慢,但是它的速度是呈指数增长(2n
)的,不久之后,它的发送速率将会变得非常快。

2、ssthresh 是 slow start threshold 的缩写; 从上图可以看出,3个事件会导致 slow start 的状态结束:1)当 cwnd 大于 slow start 的阈值; 2)超时事件; 3)收到3个重复的 ACKs,即发生 fast retransmit

你从上图可以看到,ssthresh 的值除了在初始的情况下被设置一次外,其余设置它的时候要么是超时,要么就是收到3个重复的 ACKs,而且每次它的值都被设成 ssthresh=cwnd/2,此时公式中的 cwnd 都是在网络比较拥堵时的值发送速率,因此当我们的 cwnd≥ssthresh
时,就表明我们的发送速率快要达到接近丢包的水平了,所以我们不能让发送速率呈指数增长了。因此我们进入了 congestion avoidance 状态,这个状态下的速率是呈线性增长的。

接下来让我们谈谈 congestion avoidance 这个状态的重点内容:

当它收到一个新 ACK 时,它让 cwnd=cwnd+MSS*(MSS/cwnd),这就表明这个状态下的发送速率是呈线性增长的。比如,如果当前 cwnd = 10 个 segment,因为1个 MSS 等于1个 segment,所以它必须收到10个新的 ACK 之后,才会增加1个 MSS

最后,让我们来聊一隐 fast recovery 状态:

上面我已经说过了,这个状态是推荐使用的,但并不是必须的,在早期的 TCP 版本中,TCP Tahoe,就没有这个状态,是新的 TCP 版本,TCP Reno,才有这个状态。如果大家仔细想一下,其实这个状态很合理,既然我们可以收到3个重复的 ACKs,证明丢包很有可能是先前网络状况不好的情况下引起的,目前网络状况不错。从上图我们可以看到,只有由3个重复的 ACKs 引起的 retransmit 才会进入这个状态。

下图是 Tahoe 和 Reno 2个 TCP 版本关于 congestion window 变化的对比,我们可以看到 cwnd 的初始值都是 1 MSS,即1个 segment,然后呈指数增长,紧接着越过 slow start 的阈值以后呈线性增长,在第9个 transmission round 时,由于 Tahoe 版本没有 fast recovery 状态,我们可以看到它又回到了 slow start 状态,而 Reno 进入了 fast recovery 状态。

校验和

转自:https://blog.csdn.net/xlinsist/article/details/76602294

快速重传

由于超时而引起的 retransmissions 会有一个超时时间可能会很长的问题。当一个 segment 丢失的时候,这个很长的超时时间会强制 sender 延迟 resending 丢失的 packet,因此会增加 end-to-end delay,而 Fast Retransmit 的出现就是解决这一问题的。

在上面的小节中,我已经说明了由于 out-of-order packet 的到来,receiver 会产生 duplicate ACK,并把它发送到 sender. 由于一个 sender 会连续发送大量地 packets,如果一个 packet 丢失了,sender 很有可能连续收到 duplicate ACKs. 如果一个 sender 收到的3个 duplicate ACKs 为同一个数据,它会认为这个数据对应的 packet 已经丢失了。这时,即使超时事件并没有发生,sender 也会 retransmit 这个 packet. 由于我们这回加入了 fast retransmit 这个技术。
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值