TCP/IP 协议(10):TCP 协议一百问

杨领well 的 TCP/IP 协议专栏 TCP 协议部分一直没有更新,是因为我不确定到底应该怎么来介绍 TCP 协议才能干货满满。最后我决定以 Q&A 的形式来介绍 TCP 协议,应该就不会遗漏什么了吧。
P.S. 不要问我为什么 《TCP 协议一百问》 没有一百问。 (> v <)

TCP 协议全称是 传输层控制协议(Transmission Control Protocol), 顾名思义就能知道它是 传输层协议

TCP 协议一百问

一、为什么大家常说 “TCP 协议是面向连接的,面向字节流的,可依赖的协议”?

  • 面向连接的(connection-oriented)协议: 应用程序使用 TCP 协议进行数据交换前,需要先与对端建立 TCP 连接

    我认为,所谓 TCP 连接,就是建立连接的双方知道对端的基本信息并且确认对端能够顺利地进行数据交换。

  • 面向字节流的(byte stream) 协议:TCP 协议不知道上层发送数据的格式或类型,对它而言,所有待发送的数据都只是一串字节流,没有起点和终点。
  • 可依赖的(reliable)协议:TCP 协议通过以下手段来实现数据交换的可依赖:
    (1) 应用程序发送的根据网络环境切割成合适大小的 数据段(Segment)。如果接收方发现数据有误,只需要丢弃一个数据段的数据,降低重传成本。
    (2)通过 TCP 协议发送数据之后,会等待对端发送确认信息(ACK),以保证对端已正确接收数据。
    (3)TCP 协议维护有 重传计时器(retransmission timer),指定时间内没有收到对端的确认信息,TCP 就会认为该数据段已经丢失。然后,它会重新发送该数据。
    (4)TCP 数据段的 校验和(checksum) 字段能从一定程度上保证当前数据段的正确性。
    (5)在 TCP 数据段 序列号(sequence number) 的帮助下,TCP 协议能够处理乱序到达的数据。
    (6)TCP 协议会丢弃接收到 重复数据(duplicate data)
    (7)TCP 协议提供了详细的 流量控制(flow control) 方式。

    简单总结就是:分段发送、确认和重传机制、数据段的正确性校验、乱序数据和重复数据的处理以及流量控制。

二、为什么 TCP 协议首部没有数据段总长度字段,而 UDP 协议和 IP 协议有数据报和数据包总长度的字段?

  • IP 协议 依赖的下层协议,如 以太网(Ethernet) 协议,可能有最小 帧(frame) 的要求,如果 IP 数据包(packet) 的长度小于最小帧长度,就会填充无意义的数据。因此 IP 数据包的长度不能复用 数据链路层(data link layer) 的数据帧长度,需要数据包首部有长度字段。
  • 参考文献[1]UDP 协议 的长度字段是多余的,因为它的 数据报(datagram) 长度是可以由 IP 协议的长度字段计算得出。
    我觉得由于 UDP 协议面向事务(transaction oriented) 的,因此它需要将自己的长度保存在首部,方便将可能被拆散的数据还原原本的数据报(毕竟谁也不能保证传输层协议一定总是 IP 协议)。

    The UDP Length field is redundant; the IP header contains the datagram’s total length. — 参考文献[1]

  • 由于 TCP 协议是面向数据流的,因此可以不用担心一个数据段由于传输原因被拆分成几个数据段的问题。

后续几个问题都会涉及到关于 TCP 首部(header) 的问题,因此先在此处贴上 TCP 首部的内容(下图出自 参考文献[2]):

三、URG 标识位和 Urgent Pointer 只能标识紧急数据的结束位置,那么接收端是怎么指定紧急数据的起始位置呢?

  • 答案是它并不知道,也不需要知道。

    There is no way to specify where the urgent data starts in the data stream. — 参考文献[1]

  • 由于 TCP 协议是面向字节流的,因此我们想要快速接收紧急数据,必须先将非紧急数据之前的数据都确认接收才行。
    所以 TCP 协议并不在乎紧急数据的起点在哪里,它会认为 Urgent Pointer 之前的数据都是紧急的。
  • TCP 接收到 URG 数据段之后,就会将当前状态设为 紧急模式(urgent mode), 在 (Sequence Number + Urgent Pointer) 之前的数据都会被认为是紧急数据处理(包括 Sequence Number 之前还未到达的数据)。
  • 紧急数据被处理完之后,TCP 会恢复 普通模式(normal mode) 处理后续到达的数据。
  • 题外话:处于紧急模式下的接收端收到新的 URG 数据段,会将紧急数据的结束位置更新。

    If the urgent pointer is updated while the user is in “urgent mode”, the update will be invisible to the user. — 参考文献[2]

四、URG 标识位和 PSH 标识位的区别是什么?

  • 应用程序通过设置 PSH 标识位来通知 TCP,这些数据需要尽快被发送。对端收到带有 PSH 位的数据段后,会立即将接收到的所有数据发送到应用层。

    It(PSH) is a notification from the sender to receiver for the receiver to pass all the data that it has to the receiving process. — 参考文献[1]

  • URG 标识位通知对端需要进入紧急模式,优先读取Urgent Pointer 之前的数据(PSH 则没有优先的这层意思,它只是告诉对端:“我发送的数据告一段落,你可以先将前面的数据推给应用层了”)。

五、 为什么 SYN 和 FIN 标识位需要的空数据段需要消耗一个序列号,而 ACK 和 RST 的空数据段则不需要?

因为 SYN 数据段和 FIN 数据段需要被确认(ACK),而 ACK 和 RST 数据段不需要。需要确认的数据段至少需要消耗一个序列号,以便能够确认对端接收到了该数据。

后续几个问题都会涉及到关于 TCP 的状态转换的问题,因此先在此处贴上 TCP 状态转换图(下图出自 参看文献[5]):

六、FIN_WAIT_2 被称为 Half-Close 。如果在该状态下,对端故意一直不发送 FIN 结束连接,是不是本端永远无法结束该状态?

  • TCP 协议本身对 Half-Close 没有超时限制。理论上讲对端如果恶意不发送 FIN 关闭连接,该链接将会永远处于 FIN_WAIT_2 状态。
  • 应用层非优雅关闭 socket 可以触发 RST 强制结束 FIN_WAIT_2 状态(数据接收缓冲区还有数据,直接 close 。或者 “close + 'l_onoff=1' + 'l_linger=0'”。更多详情参看 参考文献[7] 图7-12)。
  • Linux 通过 /proc/sys/net/ipv4/tcp_fin_timeout 文件来控制的超时时长。

七、TIME_WAIT 状态下接收到对端发送的数据,会做怎样的处理?

  • 如果对端发来的是 FIN 数据段,TCP 会向对端发送 ACK 数据段,然后重启 2MSL 的计时。
  • 如果对端发来的是非 FIN 数据段,TCP 会直接丢弃掉该数据段,不做任何操作。

八、TIME_WAIT 状态为什么需要等待 2MSL?

  • 假设不等待 2MSL 时间,直接将本端设为 CLOSED 状态,而此时对端先接受到了最后一次的 ACK, 然后重新和本端建立一模一样的连接。
    这时连接建立之前在网络游走的之前连接的数据传送到了本端,就会被当做是新的连接的数据被错误地解析。因此,需要等待 2MSL 时间来保证之前的连接的数据已经在网络中被丢弃。
  • 假设不等待 2MSL 时间,直接将本端设为 CLOSED 状态,而此时最后一次的 ACK 在传输过程中丢失。对端将会重传 FIN,而本端收到 FIN 后发现现在已经没有这个连接了,就会发送 RST,强制重置对端的连接。

    If the final ACK from end point 2 is dropped then the end point 1 will resend the final FIN. If the connection had transitioned to CLOSED on end point 2 then the only response possible would be to send an RST as the retransmitted FIN would be unexpected. This would cause end point 1 to receive an error even though all data was transmitted correctly. — 参考文献[6]

九、什么是 Half-Open 连接?如何识别和处理 Half-Open 的连接?(如果对端的电脑崩溃,已建立的连接会一直保持吗?)

  • TCP 连接的某端在不通知对端的情况下,单方面的关闭或中断连接,这样的连接被称为 Half-Open 连接。常见的造成 Half-Open 的原因是操作系统崩溃,强制关闭计算机电源等。

    下图展示了 Half-Open 出现的状态,出自 参考文献[8]

  • 只要不尝试通过 Half-Open 的连接发送数据,TCP 永远不会知道该连接是 Half-Open 的。这将会造成 TCP 资源的浪费。

    As long as there is no attempt to transfer data across a half-open connection, the end that’s still up won’t detect that the other end has crashed. — 参考文献[1]

  • 参考文献[7] 第7.5.5 介绍的 SO_KEEPALIVE 选项可以实现对 Half-Open 状态的探测。
    设置了该选项后,指定时间内如果没有进行过数据交换,就会进行自动向对端发送 keep-alive probe 数据段:
    (1)如果收到 ACK,则表示连接正常,不做任何处理。
    (2)如果收到 RST,则表示对端已经不存在该连接,本端也关闭连接。
    (3)如果没响应,则会在重试几次后,关闭本端的连接(认为对端不可达,连接已不存在)。

    Linux 系统在 /proc/sys/net/ipv4 路径下提供了三个文件来控制 keep-alive probe(见 参考文献[9]):

    • tcp_keepalive_time:指定多久没有进行数据交换后,发送 keep-alive probe。我的系统默认设置的是 7200(s), 即 2 小时内没做数据交换就会进行探测。
    • tcp_keepalive_intvl: 指定 keep-alive probe 没响应多久后重试。我的系统默认设置的是 75 (s),即如果没收到探测的 ACK,就会在每 75 s 重新发送探测。
      tcp_keepalive_probes: 指定 keep-alive probe 发送几次后会认为对端不可达。我的系统设置的是 9,即如果发送了 9 次探测都没有收到 ACK,就认为对端不可达。
  • 应用程序可以通过心跳算法来识别和处理 Half-Open 的连接。如 参考文献[10]

十、Half-Open 连接和 Half-Close 连接的区别是什么?

  • Half-Close 是 TCP 连接的正常状态,确认本端已没有数据需要发送,等待对端主动发送 FIN,结束连接。
  • Half-Open 是一种错误的 TCP 连接,通常是某一段异常结束导致的。
  • 从理论上来讲,处于 Half-Close 状态的连接也可能遇到 Half-Open 的情况。

十一、我们知道 TCP 的流量控制(包括拥塞控制)的算法很多,请简述各种算法是为了解决什么样的问题。

流量控制的算法当然是为了解决流量控制的问题咯。(@v@)

  • Nagle 算法延迟确认(Delayed Acknowledgment)算法 主要是为了解决小块数据传输问题,避免网络中传输的数据段都是很小的数据段。
    (1)Nagle 算法主要从发送方的角度控制小数据段的发送数量。
    (2)延迟确认算法主要从接收方的角度控制空 ACK 数据段的发送数量
  • 慢启动(Slow Start)算法拥塞避免(Congestion Avoidance)算法快速重传(Fast Retransmit)算法快速恢复(Fast Recovery) 算法, 主要是为了解决大块数传输问题。尽可能的利用网络带宽尽最大努力的传输数据,同时避免网络拥塞。
    (1)慢启动算法:在连接刚建立或者数据段发送超时的情况下,为了更快的实现更大的传输速率,用该算法来 指数 增加 拥塞窗口(congestion window,cwnd) 的大小。
    (2)拥塞避免算法:在拥塞窗口达到 ssthresh(slow start threshold size) 的情况下,为了避免更早的遇到拥塞的情况,用该算法来 线性 增加拥塞窗口的大小。
    (3)快速重传算法:当接收到同一数据段的大于或等于三个重复 ACK 时,表示该数据段已经丢失。TCP 不用等待重传计时器到期而直接重传该数据段。这个算法叫做快速重传算法。该算法尽量保证丢失的数据段尽快到达对端。
    (4)快速恢复算法:当接收到同一数据段的大于或等于三个重复 ACK 时,表示该数据段已经丢失。TCP 不直接重新开始慢启动,而是使用快速恢复算法将拥塞窗口减小到一个较大的值。这样既保持了一定的传输速度,又降低了网络的压力。

十二、为什么说 Nagle 算法和延迟确认算法一起使用会影响网络性能?

  • Nagle 算法在还有发送的数据没被 ACK 之前,尽量不发送小数据段。从而让很多不同时间段发送的小数据段可以合并成大的数据段一次发送,减少网络中小数据段的数量。
  • 延迟确认算法会等待一定的时间(如 200 ms),从而让更多的数据一次确认或者在 ACK 数据段中携带后续发送的数据,减少网络中的小数据段(空 ACK 数据段)的数量。
  • 当 Nagle 算法遇到延迟确认算法就可能会出现互相等待对方的情况:延迟确认算法想等待尽可能多的数据一次确认,Nagle 算法想等待对端的 ACK 数据段来触发小数据段的发送。因此会导致网络性能的降低。参看 参考文献[11]

十三、TCP 是怎么感知到 “拥塞控制” 的 “拥塞” 的? 如何处理这些拥塞的?

  • TCP 主要有以下渠道知道 拥塞(congestion) 情况:
    (1)重传计时器超时。
    (2)收到对端对同一个数据段的重复 ACK。
    (3)收到 ICMPsource quench 数据包。

    Using the Internet Control Message Protocol (ICMP), a source quench is a message from one host computer to another telling it to reduce the pace at which it is sending packet to that host. — 参考文献[12]

  • TCP 通过上述方式感知到拥塞对应的处理算法:
    (1)重传计时器超时和收到 source quench 数据包:慢启动算法。
    (2)收到重复 ACK:快速恢复和快速重传算法。

十四、为什么处理重传计时器超时用慢启动算法,而处理重复 ACK 用快速恢复算法和快速重传算法?

  • 接收到重复的 ACK 说明对端收到了多次后续的数据段,证明端之间的网络连接良好,可能由于网络中传输数据量较大导致网络拥塞。因此可以用快速重传和快速恢复算法在保证传输数据量的情况下,适当减少数据的发送,缓解拥塞。
  • 当重传计时器超时,说明了对端根本没收到数据或者发送的 ACK 无法到达本端。可能是网络特别拥塞或者对端已经不可达。因此需要快速的减少数据发送量的慢启动算法来慢慢试探网络状况。

    The reason for not performing slow start in this case is that the receipt of the duplicate ACKs tells TCP more than just a packet has been lost. Since the receiver can only generate the duplicate ACK when another segment is received, that segment has left the network and is in the receiver’s buffer. That is, there is still data flowing between the two ends, and TCP does not want to reduce the flow abruptly by going into slow start. — — 参考文献[1]

十五、慢启动算法是在每一次接收到 ACK 数据段后,cwnd 增加 1,可为什么总是说慢启动的 cwnd 的增长是指数级的?

  • 以 ACK 接收的数量作为横坐标来看,的确 cwnd 是线性增长的。
  • 理想情况下,刚开始,cwnd = 1, 发送方第一次发送一个数据段,等待接收到它的 ACK 数据段。当发送方接收到 ACK 数据段后,cwnd = 2, 发送两个数据段,然后等待这两个数据段的 ACK。当发送方接收到这两个 ACK 数据段后,cwnd = 4,会发送四个数据段,然后等待接收这四个数据段的 ACK。忽略发送数据前的耗时,每个轮次大约花费一个 RTT。因此以时间为单位(或 RTT),cwnd 是指数增长的。

十六、当接收窗口减小为 0 时,会通过 ACK 的 advertised window 来通知发送方,让它先暂停发送数据。那么接收窗口再次打开时,接收方如何通知发送方?如何保证该通知不会丢失?

  • 当窗口再次打开时,接收方会发送一个 ACK 数据段更新 advertised window 来通知发送方。
  • 由于 ACK 数据段是不可靠的(没有确认机制),因此,当发送方收到 advertised window 为 0 的 ACK 数据段后,会维护一个 persist timer。该计时器定期询问接收方接收窗口是否打开,直到接收窗口打开为止。

如果觉得对您有帮助,欢迎评论,点赞和关注,么么哒!

参考文献

TCP/IP 协议(10):TCP 协议一百问的更多相关文章

  1. 计算机网络(二),TCP/IP四层模型常见协议

    目录 1.应用层协议 2.传输层协议 3.网络层协议 4.链路层协议 二.TCP/IP四层模型常见协议 1.应用层协议 (1)POP3 (2)FTP (3)HTTP (4)Telnet (5)SMTP ...

  2. 08_使用TCP/IP Monitor监视SOAP协议

    [SOAP定义] SOAP   简单对象访问协议,基于http传输xml数据,soap协议体是xml格式.SOAP   是一种网络通信协议SOAP   即Simple Object Access Pr ...

  3. 使用TCP/IP Monitor监视Soap协议

    什么是soap? soap,简单对象访问协议,基于http传输xml数据,soap协议体是xml格式. SOAP 是一种网络通信协议 SOAP即Simple Object Access Protoco ...

  4. TCP/IP,HTTP,SOAP等协议之区别

    术语TCP/IP代表传输控制协议/网际协议,指的是一系列协议.“IP”代表网际协议,TCP和UDP使用该协议从一个网络传送数据包到另一个网络.把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到 ...

  5. TCP/IP笔记(二)TCP/IP简介

    上回,主要介绍了下协议和OSI参考模型,并简单了解下网络构成要素,这回该说说TCP/IP了 互联网与TCP/IP的关系   互联网进行通信时,需要相应的网络协议,TCP/IP原本就是为使用互联网而开发 ...

  6. tcp/ip学习笔记-TCP

    tcp/ip学习笔记-TCP 彭会锋 报文发送采用的是tcp_output函数,

  7. OSI参考模型与TCP/IP参考模型与TCP/IP协议栈

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484126.html OSI参考模型与TCP/IP参考模型与TCP/IP协议栈 TCP/IP分层模型 ...

  8. TCP/IP的网际层协议——ICMP

    ICMP经常被认为是IP层的一个组成部分.它携带于IP数据包中,ICMP封装在IP数据包内部: IP首部 ICMP数据包 下面是一份差错报文的例子: 最右边的+或者-代表该报文是查询报文还是错误报文. ...

  9. tcp/ip协议和http协议

    TCP/IP 是一类协议系统,它是用于网络通信的一套协议集合. 传统上来说 TCP/IP 被认为是一个四层协议:应用层(telnet, ftp, http, smtp, dns等),传输层(tcp, ...

  10. TCP/IP的排头兵――地址解析协议(ARP) (转载)

    转自:http://blog.csdn.net/wangxg_7520/article/details/2488442 一.引言 古人行军打仗,都要有一个可以引领队伍前进方向的排头兵,在TCP/IP网 ...

随机推荐

  1. NavBarControl 通过代码添加

    看到网上很多都是直接在控件上面添加的 而我的是保存在数据库读取后添加的. 后来自己摸索了一下. 通过代码添加 navBarControl1.Groups.Add(new NavBarGroup( st ...

  2. Qwt开发笔记(一):Qwt简介、下载以及基础demo工程模板

    前言   QWT开发笔记系列整理集合,这是目前使用最为广泛的Qt图表类(Qt的QWidget代码方向只有QtCharts,Qwt,QCustomPlot),使用多年,系统性的整理,本系列旨在系统解说并 ...

  3. Java9-17新特性一览,了解少于3个你可能脱节了

    前言 Java8出来这么多年后,已经成为企业最成熟稳定的版本,相信绝大部分公司用的还是这个版本,但是一眨眼今年Java19都出来了,相信很多Java工程师忙于学习工作对新特性没什么了解,有的话也仅限于 ...

  4. SAP程序发布流程

    更改程序名称 如果你想要更改程序名称的话,首先进入程序,关闭编辑,只显示代码 点击重命名就可以了 或者直接输入事务代码se38进入APAP编辑器,输入程序名称,重命名 为程序创建事务代码 事务代码为s ...

  5. ATM项目

    ATM项目实战 项目需求分析: 1.注册(密码要加密) 2.登陆 3.查看余额 4.提现(可自定手续费) 5.还款 6.转账 7.查看流水 8.添加购物车功能 (商品可配置) 9.查看购物车功能 10 ...

  6. 如何通过 C#/VB.NET 将 PDF 转为 Word

    众所周知,PDF 文档支持特长文件,集成度和安全可靠性都较高,可有效防止他人对 PDF 内容进行更改,所以在工作中深受大家喜爱.但是在工作中,我们不可避免的会对 PDF 文档进行修改或再编辑,这时我们 ...

  7. Vue3.0 生命周期

    所有生命周期钩子的this上下文都是绑定至实例的. beforeCreate:在实例初始化之后.进行数据帧听和事件/侦听器的配置之前同步调用. created:实例创建完成,主要包括数据帧听.计算属性 ...

  8. 关于 MySQL 嵌套子查询中,无法关联主表字段问题的折中解决方法

    今天在工作中写项目的时候,遇到了一个让我感到几乎无解的问题,在转换了思路后,想出了一个折中的解决方案,记录如下. 其实,问题的场景,非常简单: 就是需要查询出上图的数据,红框是从 项目产品表 中查询的 ...

  9. [深度学习] Python人脸识别库Deepface使用教程

    deepface是一个Python轻量级人脸识别和人脸属性分析(年龄.性别.情感和种族)框架,提供非常简单的接口就可以实现各种人脸识别算法的应用.deepface官方仓库为deepface.deepf ...

  10. 在 NGINX 中根据用户真实 IP 进行限制

    需求 需要根据用户的真实 IP 进行限制, 但是 NGINX 前边还有个 F5, 导致 deny 指令不生效. 阻止用户的真实 IP 不是 192.168.14.* 和 192.168.15.* 的访 ...