TCP协议解析

目录

1.几个概念

  • 自动重复请求(Automatic Repeat Request,ARQ):使信息在信道里尽量免于出错,一种简单的方法是“尝试重新发送”,直到消息被最终接收。(另一种是使用差错校正码,添加一些冗余码,使即时某些比特被毁,真实的信息也可以被恢复)

使用ARQ需要有一种方法来判断:(1)接收方是否已收到分组;(2)接收方接收到的分组是否与之前发送方发送的一样。
为此接收方法需要给发送方发送确认接收的信号,称为确认(acknowledgment),或ACK

这样处理的一个基本流程应为:发送方发送一个分组,然后等待一个ACK。当接收方接收到这个分组时,它发送对应的ACK。当发送方法接收到这个ACK,它再发送另一个分组。
但仅是这样会存在一些值得关注的问题

  1. 发送方对一个ACK应该等待多长时间?
  2. 如果ACK丢失了怎么办?
  3. 如果分组被接收到了,但里面有错怎么办?

第一个问题并不容易解决,这涉及重传超时的设置,它通常会根据RTT(往返时间)来估计。第二个问题可以比较简单的解决,当一个ACK丢失了,发送方会简单的再次发送原分组(因为它并没有收到该分组的ACK)。这样接收方需要为此准备好解决可能会接收到两个或更多的拷贝的问题,为每个分组加入序列号。第三个问题,需要借助差错差错检验码,如果分组有差错就不回复该分组的ACK。

目前所介绍的协议是可靠的。但效率不高,这种方式称为“停止和等待”,发送方注入一个分组到通信路径,然后停下来等待ACK。该协议的吞吐量性能(每单位时间发送在网络中的数据量)与M/R成正比,M为分组大小,R为往返时间(RTT)。如果考虑分组丢失和损害的情况,性能会进一步降低。

为此引入一种解决方法和一个新概念:

  • (分组)窗口:为已被发送方法注入(发送方可以注入多个)但还没有完成确认的分组(或它们的序列号)的集合。
  • 滑动窗口:这其实是一个协议或称为方法。窗口滑动意味着,窗口前的分组都被确认,窗口后的分组不能被发送直到窗口向右滑动。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OzOG5xMv-1572959439420)(./resources/image/03/03-1.jpg)]

  • 流量控制和拥塞控制:这都涉及到了窗口大小的控制,需要通信双方共同协调(另一种不基于窗口的控制是直接改变发送方的速率)。基于窗口的通信速率理想情况下正比于(SW/R)b/s,W表示窗口大小,S是分组大小,R是往返时间(RTT)。
    流量控制:流量控制关注的是发送方法发送速度和接收方处理速度的协调
    拥塞控制:是为了解决中间网络的拥堵,如果丢包过多会严重影响性能

2.TCP协议

TCP提供了一种面向连接的、可靠的字节流服务。TCP提供的是双工服务。TCP为应用程序提供了一种字节流抽象的概念,没有保护消息边界。

无保护消息边界的举例:如果应用程序在一端写入10字节,随后写入20字节,再随后写入50字节,那么在另一端的应用程序是不知道每次写入的字节是多少的。另一端可能会以每次20字节分四次读入这80字节或以一些其他方式读入。一端给TCP输入字节流,同样的字节流会出现在另一端。每个端点独立选择字节的读和写大小。

  • 面向连接:指的是使用TCP的两个应用程序必须在它们交换数据之前,通过相互联系来建立一个TCP连接。在TCP中是一个虚连接,在网络中表现为逻辑信道。

  • 组包(packetization):TCP提供的是一个字节流接口,因此TCP必须把一个发送应用程序的字节转换成一组IP可以携带的分组,这个工作是由TCP协议做的。即组包,组包是一个动作

  • 序列号:这些分组包含序列号,该序列号在TCP中实际代表了每个分组的第一个字节在整个数据流中的字节偏移量(以1B为单位)(注意区分:并不是ip协议里的偏移字段),而不是分组号。
    这样做的好处:允许分组在传送中是可变大小的,并允许它们组合,称为重新组包(repacketization)。

  • 报文段(segment):应用程序数据将会被打散成TCP认为的最佳大小的块进行发送,一般使得每个报文段按照不会被分片的单个IP层数据报的大小来划分。由TCP传给IP的块称为报文段。TCP报文段是组包的结果
    UDP是不同的,UDP应用程序每次写入通常就产生一个UDP数据,其报文段(或叫做UDP数据报)的大小就是写入的数据加上UDP首部。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPHZIOq4-1572959439423)(./resources/image/03/03-2.png)]

  • 重传计时器:TCP不会为每个报文段设置一个不同的重传计时器。当发送一个窗口的数据,它只设置一个计数器,当ACK到达时再更新超时

  • 对ACK的处理:接收端接收到数据是一般会延迟片刻。ACK是积累的,一个指示字节号N的ACK意味着N前面的所有字节都已成功接收。为ACK丢失带来了一定的鲁棒性

2.1 TCP首部

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQvWw0Wx-1572959439423)(./resources/image/03/03-3.jpg)]

[d8 ce 3a 8c d6 51|1c 4d 70 3a 52 c3|08 00][45 00|
 00 28|ae 5f|40 00|80|06|8d 53|c0 a8 2b 5e|80 01
 53 15][c3 de|01 bb|01 99 09 bf|96 9e 40 0d|50 10|
 fa f0|4e 29|00 00]

从c3de开始到末尾为TCP首部

  • 源端口:16bytes。例如:0xc3deH(50142)。

  • 目标端口:16bytes。例如:0x01bbH(433)。

  • 序列号:32bytes。例如:0x019909bfH(这是一个第三次握手的报文,此次的相对偏移量是1)。当建立一个新连接时,从客户端发送至服务端的第一个报文段的SYN位字段被启用。该方向上的第一个序列号,将被包含在该报文段中。注意这个数字不是0或1,而经常是随机选择的一个数,称为初始序列号(Initial Sequence Number,ISN)。序列号到达2^32-1后在循环到0

  • 确认号:32bytes。例如:0x969e400dH(此次相对偏移量是1)。确认号是接收到对方的报文段后,返回的已被确认正确接收的序列号。SYN段和FIN段被设置为1时会被当做占用一个字节看待。

注意:这里的序列号和确认号是值得关注的,它们字节应该如何赋值和计算的应该被了解,在下面说到TCP连接时会具体进行分析,在了解这个工程时应该时刻记得,TCP是双工服务,数据向两个方向流动,且两个方向互相独立。

  • 头部长度:4bytes。0x5H(5)。以4B为单位。

  • 标志字段:这里面有12位,我们常理解的是后6位,现在都提一下。

    1. Reserved:3bytes保留。
    2. NC(nonce):暂不清楚,英文翻译是临时的,偶造的,只使用一次的
    3. CWR(Congestion Window Reduced):拥塞窗口减少(发送方降低它的发送速率)
    4. ECE(ECN-Echo):ECN回显,用于拥塞控制(发送方接收到了一个更早的拥塞通告)
    5. URG(Urgent):紧急(紧急字段有效)
    6. ACK(Acknowledgment):确认,确认号字段有效。
    7. PSH(Push):推送,接收方进快给应用程序传送这个数据,(没有被可靠的实现或使用)
    8. RST(Reset):重置连接,连接取消,经常因为错误
    9. SYN(syn):用于初始化一个连接的同步序列号
    10. FIN(FIN):该报文段的发送方已结束向对方发送数据。
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5ML01KK-1572959439425)(./resources/image/03/03-5.jpg)]
  • 窗口大小:16bytes。例如:0xfaf0H(64240)。接收端当前能够接收的字节数(即当前允许发送端发送的字节数),流量控制由每个端点使用窗口大小字段来通告一个窗口大小来完成。指定的是字节数,16位限制了它最大为,65535字节。
    由于现在带宽增大,该数已经不够用了,由此有了**Window scale(WS)**选项,可以把这个叫做窗口扩大因子,该选项只出现在SYN报文段中。为了兼容仅当双方都发送WS才生效,SYN报文段中,WS还未生效。窗口大小左移WS的数值即为真正的窗口大小。

  • TCP校验和:16bytes。(wireshark抓取的校验和是不正确)校验和的计算方法与IP、ICMP、UDP一样。计算数据包括:TCP首部+TCP数据+TCP伪首部,如下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyLBvHtX-1572959439426)(./resources/image/03/03-4.png)]

  • 紧急指针(Urgent Pointer):在URG开启时有效,该字节加到报文段的序列号字段,得到是紧急数据的最后一个字节的序列号。

  • 可选字段:一个常见的选项字段是“最大段大小”,称为MSS。连接的每个端点一般在它发送的第一个报文段(即SYN字段被设置的那个报文段)上指定。作用:MSS指定该选项的发送者在相反方向上希望接收到的报文段负载数据的最大值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yADaOWYQ-1572959439427)(./resources/image/03/03-6.png)]

3. TCP连接管理

一个TCP的连接由一个4元组构成,分别为两个IP地址和两个端口。
一个TCP连接通常分为3个阶段:

  1. 连接建立(三次握手)
  2. 数据传输
  3. 连接关闭(四次挥手)

3.1 连接建立

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HqNfPrx6-1572959439430)(./resources/image/03/03-7.jpg)]

第一次握手:客户端发送一个SYN报文段,指明想要连接的端口号和客户端初始序列号(ISN©,在图中即为x),通常,客户端还会借此发送一个或多个选项,MSS一般就会在此次发送。
第二次握手:在服务段接收到客户端发来的SYN报文段后,会发送自己的SYN报文段作为响应,并包含了服务端的初始序列号(ISN(s),在图中即为y)。此外,还需告诉客户端,它确认接收了客户端发来是SYN报文段,服务端将取出ISN(c)数值并加1作为返回的ACK数值。因此,每发送一个SYN,序列号就会加1.如果出SYN报文段出现现丢包,该SYN段会重传。
第三次握手:为了确认服务器的SYN,客户端将取出ISN(s)的数值加1后作为返回的ACK数值。

通俗讲三次握手(C表示客户端,S表示服务端):

  1. C说:“你收得到我的消息吗?我可以和你建立连接吗?”
  2. S说:“我可以收到你的消息!我们可以建立连接!那么你可以收到我的消息吗?”
  3. C说:“我可以收到你的消息!”

三次握手告诉了连接双方什么:

客户端服务端
第一次握手只知道自己向服务端发送了一个SYN报文段,其他什么也不知道有一个客户端想要建立连接,且我能收到客户端的消息
第二次握手服务端能收到我的消息,且我也能收到客户端的消息,这个时候作为上帝视角,已经可以知道双方线路是完好的,但服务端却还不能确定客户端能够收到它的消息,所以客户端还需要回复确认,进行第三次握手还不能知道什么
第三次握手我要准备收发数据了客户端能收到我的消息,前面已经知道我能收到客户端的消息,我要准备收发客户端的数据了

其实双方知道的信息不只有这些,在建立TCP连接时,双方不仅会维护连接状态,通信双方通常会交换一些选项,MSS也只是其中之一。

现在放上一些我通过wireshark抓到了连接建立时的TCP报文。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lb6SXSvZ-1572959439432)(./resources/image/03/03-8.jpg)]

  • 第一次握手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5IUb1LR7-1572959439434)(./resources/image/03/03-9.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKhzGmrN-1572959439435)(./resources/image/03/03-10.png)]

选项(Options):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nNxaflFN-1572959439438)(./resources/image/03/03-11.png)]


  • 第二次握手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6UMK7wuR-1572959439440)(./resources/image/03/03-12.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37ch7kIF-1572959439440)(./resources/image/03/03-13.png)]

选项(Options):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IdrjYJyn-1572959439442)(./resources/image/03/03-14.png)]


  • 第三次握手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6R8q1EuD-1572959439444)(./resources/image/03/03-15.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mFzpzHWa-1572959439445)(./resources/image/03/03-16.png)]


现在重点来看一下标志位、Seq和ACK
第一次:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1HrkzWXf-1572959439448)(./resources/image/03/03-17.png)]
第二次:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1AASLYcs-1572959439450)(./resources/image/03/03-18.png)]
第三次:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8nLULYlF-1572959439452)(./resources/image/03/03-19.png)]

3.2 连接关闭

连接的任何一方都可以发起一个关闭操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FkfS0c71-1572959439454)(./resources/image/03/03-20.png)]

TCP连接完全关闭经过四次挥手:

第一次挥手:连接的主动关闭者发送一个FIN段,并会携带上当前的序列号(图中表现为u)。还会包含一个ACK段用于确认对方最近一次发来的数据(图中没有表示,我们记为L)。
第二次挥手:连接的被动关闭者,将接收的序列号加一后作为响应的ACK值(u+1),并携带序列号(图中v=L),表明它已经成功接收到主动关闭者发送的FIN。此时上层应用将被告知连接的另一端已经提出了关闭的请求。(通常,这将导致应用程序发起自己的关闭操作)。
第三次挥手:接着,被动关闭者转变为主动关闭者,将发送自己的FIN。该报文段的序列号为L(图中v=w=L),ack同样为u+1。
第四次挥手:为了完成连接的关闭,最后发送的报文段将包含一个ACK用于确认上一个FIN(图中表现为w+1),并带上序列号(u+1)。如果发送FIN丢失了,那么发送方将重新传输直到接收到一个ACK确认为止。

通俗的讲TCP连接关闭(A为主动,P为被动):

A说:“我想要关闭连接了(协商),你收到回复一下。”
P说:“我收到了,那我不再等待读入你的数据了。”
A说:“嗯嗯!我现在不再写入数据了(确认)”

P说:“我们断开连接吧(协商),我这儿没有消息想要告诉你了,你收到回复一下”
A说:“好!那我不再等待读入你的数据了!(心想:我再等一会儿,它要没收到就不好了)”
P说:“嗯嗯!我不再写入数据了(确认)”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYZqJBq6-1572959439456)(./resources/image/03/03-21.jpg)]

TCP是支持半关闭的,但只进行前两次挥手时,数据还能够从被动关闭方发送给主动关闭方。

还有两种情况也是可能出现的,也是被TCP允许的:同时打开和同时关闭。(放两张图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ide1L4ei-1572959439458)(./resources/image/03/03-22.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIhBDfK5-1572959439460)(./resources/image/03/03-23.jpg)]

连接状态转换图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LNeLYnUa-1572959439462)(./resources/image/03/03-24.jpg)]

具体的连接关闭的数据报分析就不再做了,可以自己抓包看看,就只放下面这样的一张图了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l8dn3HWV-1572959439464)(./resources/image/03/03-25.PNG)]

4. TCP连接的其他问题

TCP是相当复杂化的一个协议,我上面写到的只是冰山一角,TCP协议中还考虑到了:

  • 初始序列号:这个序列号并不向想象中的那么简单,它其实被TCP协议给予了较高的重视程度,一个TCP报文段只有同时具备连接的4元组与当前活动窗口的序列号,才会再通信过程中被对方认为是正确的。也就是说序列号还涉及到连接的安全问题和连接正确性问题。

  • 连接建立超时:超时时间是动态的。这里我想说的是,在连接建立后是没有超时的(应用程序可以自己加一个),即使没有数据传输也会保持连接。这其实也是导致半开连接的一个原因。

  • TCP的许多选项:我们前面已经提到了3个,还有一些其他选项。

  • TCP的路径最大传输单元发现,这也是一个很重要的功能。

  • 半开连接:这是我在这里最想关注的问题。半开连接是一端处于监听状态,而另一端已经被关闭了,《TCP详解卷一》是这样说的:如果在__未告知__另一端的情况下通信的一端关闭或终止连接,那么就认为该条TCP连接处于半开状态。
    这种情况发生通信一方的主机崩溃(非正常关机,网络断开等任何使FIN端发不出去的情况)的情况下。只要不尝试通过半开连接传输数据,正常工作的一端就不会检测出另一端已经奔溃。我认为这样的情况值得网络应用开发人员关注。

  • 与TCP连接管理相关的攻击:SYN泛洪(解决方法与序列号有关)、伪造ICMP PTB消息(使MTU非常小)、序列号攻击。

  • TCP超时和重传细节

  • 窗口管理

  • 拥塞控制

注:想要学习TCP更多的细节,可以去看《TCP协议卷一》这本书,这本书写的很详细,详细意味着其中的内容很多,当然有一些人认为这本书生涩难懂。我保持中立,我读了,没有全读,我看这本书的目的是为了提高我在网络编程上的理解和能力,事实上我也确实知道了许多原来不知道的知识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值