Tcp 协议

Tcp 和 Udp的区别是什么?

Tcp是一个面向连接的、可靠的、基于字节流的传输层协议。
Udp是一个面向无连接的传输层协议。

Tcp的3大核心特性:

1、面向连接:Tcp需要三次握手建立连接
2、可靠性:有状态-Tcp会精准的记录哪些数据发送了,哪些数据被接受了,哪些数据没有被收到,而且保证数据包按序到达。可控制-当丢包或者网络环境不佳的时候,Tcp会根据具体的情况调整自己的行为,控制自己的发送速度或者重发。
3、面向字节流:Tcp为了维护状态,将一个个IP包变成了字节流。

Tcp的三次握手:

1、双方都处于closed状态。服务端打开端口监听进入listen状态。
2、客户端发起链接,发送SYN信号,进入SYN-SEND状态。
3、服务端收到SYN信号后,返回SYN和ACK信号,进入SYN-RCVD状态。
4、客户端收到ACK信号后,返回ACK信号,进入ESTABLISHED状态。
5、服务端收到ACK信号,进入ESTABLISHED状态。
从图上可以看到客户端发送SYN seq=x,在ACK ack=x+1并添加SYN seq=y,凡是需要对端确认的,一定消耗TCP报文的序列号。SYN需要对端的确认,而ACK不需要,因此SYN消耗一个序列号,而ACK不消耗。
三次握手的过程中,只有第三次可以携带数据,第三次握手的时候,客户端已经处于ESTABLISHED状态,并且能够确认服务器的状态,相对前两次而言安全,可以携带数据。

Tcp的四次挥手

1、双方处于ESTABLISHED状态,客户端发送FIN信号,进入FIN-WAIT-1状态。
2、服务端接收到FIN信号后,返回ACK信号,进入CLOSE-WAIT状态后发送ACK信号和FIN信号,并转为LAST-ACK信号。
3、客户端接收到ACK信号后进入FIN-WAIT-2状态,再接收到FIN+ACK信号后,进入TIME-WAIT状态,并返回ACK信号,等待2MSL(Maximum Segment Lifetime,报文最大生存时间,在这段时间内如果客户端没有收到服务端的重发请求,那么表示ACK成功,挥手结束,否则客户端重发ACK)后进入CLOSED状态。
4、服务端接收到ACK信号后CLOSED。

为什么要等待2MSL?
  • 1个MSL确保四次挥手中主动关闭方最后的ACK报文最终能达到对端
  • 1个MSL确保对端没有收到ACK重传的FIN报文可以到达
半连接队列:

当客户端发送SYN信号到服务端,服务端收到以后恢复ACK和SYN,状态有LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,也就是半连接队列。

全连接队列:

当客户端返回ACK后,服务端接收,三次握手完成。这个时候连接等待被具体的应用取走,在被取走之前,它会被退出另一个TCP维护的队列,也就是全连接队列。

SYN Flood攻击原理:

使用客户端在短时间内伪造大量不存在的IP地址,并向服务器端发送SYN。对服务端而言:
1、需要处理大量的SYN包并且返回对应的ACK,会出现大量处于SYN_RCVD状态的连接,从而占满整个半连接队列,导致无法处理正常请求。
2、由于IP是虚假的,服务端长时间收不到客户端的ACK,会一直尝试重新发送数据,直到耗尽资源。
如何应对:
1、增加半连接队列的容量。
2、减少SYN+ACK重试次数,避免大量的超时重发。
3、利用SYN Cookie技术,服务端接收到SYN后不立即分配链接资源,而是根据SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上Cookie值,服务端验证Cookie合法之后才分配连接资源。

Tcp报文头部的字段:

如何标识一个连接?
通过Tcp连接的四元组——源IP,源端口,目标IP,目的端口。

Tcp报文为什么没有源IP和目的IP?
在IP层已经对IP进行处理,Tcp只需要记录端口。

数据序号是本报文段第一个字节的序列号,是长为4个字节的无符号整数,表示范围为0~2^32-1,序列号在通信过程中有两个作用:
1、在SYN报文中交换彼此的初始序列号。
2、保证数据包按正确的顺序组装。

ISN即Initial Sequence Number(初始序列号),在三次握手的过程当中,双方会用过SYN报文来交换彼此的 ISN。
ISN 不是一个固定的值,而是每 4 ms 加一,溢出则回到 0,这个算法使得猜测 ISN 变得很困难。

确认序号即ACK(Acknowledgment number)。用来告知对方下一个期望接收的序列号,小于ACK的所有字节已经全部收到。

标记位有SYN,ACK,FIN,RST,PSH。
FIN:即 Finish,表示发送方准备断开连接。
RST:即 Reset,用来强制断开连接。
PSH:即 Push, 告知对方这些数据包收到后应该马上交给上层的应用,不能缓存。

窗口大小占用两个字节,也就是 16 位,但实际上是不够用的。因此 TCP 引入了窗口缩放的选项,作为窗口缩放的比例因子,这个比例因子的范围在 0 ~ 14,比例因子可以将窗口的值扩大为原来的 2 ^ n 次方。

校验和占用两个字节,防止传输过程中数据包有损坏,如果遇到校验和有差错的报文,TCP 直接丢弃之,等待重传。

可选项
常用的可选项有以下几个:
TimeStamp: TCP 时间戳,后面详细介绍。
MSS: 指的是 TCP 允许的从对方接收的最大报文段。
SACK: 选择确认选项。
Window Scale:窗口缩放选项。

Tcp快速打开的原理(TFO)

首轮三次握手(没有Cookie):
1、客户端发送SYN给服务端,服务端接收到。
2、服务端通过计算得到一个SYN Cookie,将这个Cookie放到 TCP 报文的 Fast Open选项中,返回给客户端。
3、客户端拿到这个 Cookie 的值并缓存。
4、正常完成三次握手。
后续三次握手(有Cookie):
1、客户端会将之前缓存的 Cookie、SYN 和HTTP请求发送给服务端。
2、服务端验证了 Cookie 的合法性,如果不合法直接丢弃;如果是合法的,那么就正常返回SYN + ACK并向客户端发 HTTP 响应。
3、正常完成三次握手。
TFO 的优势并不在之后的握手,在拿到客户端的 Cookie 并验证通过以后,可以直接返回 HTTP 响应,充分利用了1 个RTT(Round-Trip Time,往返时延)的时间提前进行数据传输,积累起来也是一个比较大的优势。

Tcp报文的时间戳

TimeStamp是 TCP 报文首部的一个可选项,一共占 10 个字节:
kind(1 字节) + length(1 字节) + info(8 个字节)
其中 kind = 8,length = 10,info 有两部分构成:TimeStamp和TimeStamp Echo,各占 4 个字节。
Tcp的时间戳主要解决两大问题:

  • 计算往返时延 RTT(Round-Trip Time)
  • 防止序列号的回绕问题
Tcp的超时重传时间

TCP 具有超时重传机制,即间隔一段时间没有等到数据包的回复时,重传这个数据包。这个重传间隔也叫做超时重传时间(Retransmission TimeOut, 简称RTO)。

Tcp的流量控制

对于发送端和接收端而言,TCP 需要把发送的数据放到发送缓存区, 将接收的数据放到接收缓存区。
而流量控制索要做的事情,就是在通过接收缓存区的大小,控制发送端的发送。如果对方的接收缓存区满了,就不能再继续发送了。

Tcp的拥塞控制

对于拥塞控制来说,TCP 每条连接都需要维护两个核心状态:
1、拥塞窗口(Congestion Window,cwnd)
2、慢启动阈值(Slow Start Threshold,ssthresh)
涉及到的算法有这几个:
1、慢启动
2、拥塞避免
3、快速重传和快速恢复

拥塞窗口(Congestion Window,cwnd)是指目前自己还能传输的数据量大小。
那么之前介绍了接收窗口的概念,两者有什么区别呢?
接收窗口(rwnd)是接收端给的限制(限制发送窗口的大小 = min(rwnd, cwnd))
拥塞窗口(cwnd)是发送端的限制

拥塞控制首先就是要采用一种保守的算法来慢慢地适应整个网路,这种算法叫慢启动。
1、三次握手,双方宣告自己的接收窗口大小。
2、双方初始化自己的拥塞窗口(cwnd)大小。
3、在开始传输的一段时间,发送端每收到一个 ACK,拥塞窗口大小加 1,也就是说,每经过一个 RTT,cwnd 翻倍。如果说初始窗口为 10,那么第一轮 10 个报文传完且发送端收到 ACK 后,cwnd 变为 20,第二轮变为 40,第三轮变为 80,依次类推。它翻倍的阈值叫做慢启动阈值,超过这个值之后就需要拥塞避免了。

拥塞避免:
原来每收到一个 ACK,cwnd 加1,现在到达阈值了,cwnd 只能加这么一点: 1 / cwnd。那你仔细算算,一轮 RTT 下来,收到 cwnd 个 ACK, 那最后拥塞窗口的大小 cwnd 总共才增加 1。
也就是说,以前一个 RTT 下来,cwnd翻倍,现在cwnd只是增加 1 而已。

快速重传:
在 TCP 传输的过程中,如果发生了丢包,即接收端发现数据段不是按序到达的时候,接收端的处理是重复发送之前的 ACK。
比如第 5 个包丢了,即使第 6、7 个包到达的接收端,接收端也一律返回第 4 个包的 ACK。当发送端收到 3 个重复的 ACK 时,意识到丢包了,于是马上进行重传,不用等到一个 RTO 的时间到了才重传。
这就是快速重传,它解决的是是否需要重传的问题。

选择性重传
那你可能会问了,既然要重传,那么只重传第 5 个包还是第5、6、7 个包都重传呢?
当然第 6、7 个都已经到达了,TCP 的设计者也不傻,已经传过去干嘛还要传?干脆记录一下哪些包到了,哪些没到,针对性地重传。
在收到发送端的报文后,接收端回复一个 ACK 报文,那么在这个报文首部的可选项中,就可以加上SACK这个属性,通过left edge和right edge告知发送端已经收到了哪些区间的数据报。因此,即使第 5 个包丢包了,当收到第 6、7 个包之后,接收端依然会告诉发送端,这两个包到了。剩下第 5 个包没到,就重传这个包。这个过程也叫做选择性重传(SACK,Selective Acknowledgment),它解决的是如何重传的问题。

快速恢复
当然,发送端收到三次重复 ACK 之后,发现丢包,觉得现在的网络已经有些拥塞了,自己会进入快速恢复阶段。
在这个阶段,发送端如下改变:
1、拥塞阈值降低为 cwnd 的一半
2、cwnd 的大小变为拥塞阈值
3、cwnd 线性增加

Nagle 算法的规则如下:

1、当第一次发送数据时不用等待,就算是 1byte 的小包也立即发送
2、后面发送满足下面条件之一就可以发了:
3、数据包大小达到最大段大小(Max Segment Size, 即 MSS)
4、之前所有包的 ACK 都已接收到

延迟确认

试想这样一个场景,当我收到了发送端的一个包,然后在极短的时间内又接收到了第二个包,那我是一个个地回复,还是稍微等一下,把两个包的 ACK 合并后一起回复呢?
延迟确认(delayed ack)所做的事情,就是后者,稍稍延迟,然后合并 ACK,最后才回复给发送端。TCP 要求这个延迟的时延必须小于500ms,一般操作系统实现都不会超过200ms。
不过需要主要的是,有一些场景是不能延迟确认的,收到了就要马上回复:
1、接收到了大于一个 frame 的报文,且需要调整窗口大小
2、TCP 处于 quickack 模式(通过tcp_in_quickack_mode设置)
3、发现了乱序包
Nagle算法和延迟确认,前者意味着延迟发,后者意味着延迟接收,同时使用会造成更大的延迟,产生性能问题。

Tcp 的 keep-alive

Tcp的keep-alive的作用就是探测对端的连接有没有失效,通常是7200s检测一次。
站在应用的角度:
1、7200s 也就是两个小时检测一次,时间太长
2、时间再短一些,也难以体现其设计的初衷, 即检测长时间的死连接
所以大部分的应用并没有默认开启 TCP 的keep-alive选项。

参考文献

TCP协议面试灵魂10问,建议收藏~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,321评论 6 543
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,559评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,442评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,835评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,581评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,922评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,931评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,096评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,639评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,374评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,591评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,104评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,789评论 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,196评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,524评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,322评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,554评论 2 379