You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
我们需要知道就是TCP在网络OSI的七层模型中的第四层——传输层(Transport Layer),IP在第三层——网络层(Network Layer),ARP在第二层——数据链路层(Data Link Layer),在第二层上的数据,我们叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment。
我们知道当数据数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端。
以太网数据包(packet)的大小是固定的,最初是1518字节,后来增加到1522字节。其中, 1500 字节是负载(payload),22字节是头信息(head)。
IP 数据包在以太网数据包的负载里面,它也有自己的头信息,最少需要20字节,所以 IP 数据包的负载最多为1480字节。
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。
TCP Head
我们先了解TCP协议Head部分的格式:
理解其中每个字段含义是我们了解TCP的基础知识,所以耐心点我们一个一个了解吧。
Source Port & Destination Port
Source Port 和 Destination Port分别占用16位,表示源端口号和目的端口号。
我们可以发现三次握手,主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN(同步序号),全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个序号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
关于ISN即seq的初始化,我们前面在介绍seq的时候我们说过这个初始数值为一个随机数。
为什么不能hard code 呢?
用一个例子来解释:
如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。这样就全乱了。所以需要一个不重复的随机数来作为初始值。
第一次分手:client向TCP发出连接释放报文段,并停止发送数据,主动关闭TCP连接。client设置seq = x + 2和ACK = y + 1,将连接释放报文首部终止控制位FIN置为1。此时,client进入FIN_WAIT_1(终止等待状态1)状态,等待server确认。
第二次分手:server收到了连接释放报文后即发出确认报文,ACK = x + 3(为seq加1)。server进入CLOSE_WAIT(关闭等待)状态。此时TCP连接处于半关闭状态,即client已经没有数据要发送了,但是server发送数据client任然接受,也就是server到client方向连接还没有关闭。client收到来自server的确认报文ACK后,就进入FIN_WAIT 2(终止等待2)状态,等待server发送连接释放报文
第三次分手:server已经没有数据要发送了,通知TCP释放连接。server发送释放报文段,设置FIN为1,seq = y + 1和上次发送过的ACK = x + 3。然后server进入LAST_WAIT(最后确认状态)状态,等待client确认。
第四次分手:client收到server发送的连接释放报文段后,必须发出确认报文。client在报文中ACK = y + 2,seq = x + 3然后进入TIME_WAIT状态。server收到client确认报文段以后,就关闭连接CLOSED。此时,client等待2MSL后依然没有收到回复,则证明server端已正常关闭,那么,client也关闭连接CLOSED。
https://wolfdu.fun/post?postId=5a6aba12b890b156d0fae649
TCP是什么?
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
它是一个非常复杂的协议,这里只是简述一些相关信息,如果想系统学习整个协议还是需要静下心来读一读TCP/IP详解 卷1:协议。
OSI参考模型
首先我们应该先了解下OSI参考模型:
OSI(Open System Interconnect),即开放式系统互联,一般叫OSI参考模型。
每一层实现各自的功能和协议,并完成与相邻层的接口通信。OSI的服务定义详细说明了各层所提供的服务。某一层的服务就是该层及其下各层的一种能力,它通过接口提供给更高一层。各层所提供的服务与这些服务是怎么实现的无关。
下面列出每层的作用以及对应的协议:
我们需要知道就是TCP在网络OSI的七层模型中的第四层——传输层(Transport Layer),IP在第三层——网络层(Network Layer),ARP在第二层——数据链路层(Data Link Layer),在第二层上的数据,我们叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment。
那么TCP 协议的作用是什么?
简而言之,TCP提供可靠的连接服务,保证数据通信的完整性和可靠性,防止丢包。
如果我们想要更进一步的了解TCP协议,那么我们就需要了解该协议中各个实现细节,我们先看看TCP数据包里面有些什么。
TCP数据包
我们知道当数据数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端。
以太网数据包(packet)的大小是固定的,最初是1518字节,后来增加到1522字节。其中, 1500 字节是负载(payload),22字节是头信息(head)。
IP 数据包在以太网数据包的负载里面,它也有自己的头信息,最少需要20字节,所以 IP 数据包的负载最多为1480字节。
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。
TCP Head
我们先了解TCP协议Head部分的格式:
理解其中每个字段含义是我们了解TCP的基础知识,所以耐心点我们一个一个了解吧。
Source Port & Destination Port
Source Port 和 Destination Port分别占用16位,表示源端口号和目的端口号。
用于区别主机中的不同进程,而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址(Source Address)和目的IP地址(Destination Address)就能唯一的确定一个TCP连接。
IP-Head格式:
Sequence Number
该字段用来标识从TCP发端向TCP收端发送的数据字节流中的的第一个数据字节在数据流中的序号,表示TCP 数据包的编号,用来解决网络包乱序(reordering)问题。
一个包1400字节,那么一次性发送大量数据,就必须分成多个包。比如,一个 10MB 的文件,需要发送7100多个包。
发送的时候,TCP 协议为每个包编号(sequence number,简称 Seq),以便接收的一方按照顺序还原。万一发生丢包,也可以知道丢失的是哪一个包。
第一个包的编号是一个随机数。为了便于理解,这里就把它称为1号包。假定这个包的负载长度是100字节,那么可以推算出下一个包的编号应该是101。这就是说,每个数据包都可以得到两个编号:自身的编号,以及下一个包的编号。接收方由此知道,应该按照什么顺序将它们还原成原始文件。
Acknowledgment Number & Window
Acknowledgment Number:就是ACK,32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1,主要用来解决丢包的问题。不过,只有当标志位中的ACK标志为1时该确认序列号的字段才有效。
Window: 窗口大小,也就是有名的滑动窗口,用来进行流量控制(这块内容比较多需要单独开坑,这里简单带过)。
从一个场景来了解这两个字段:
服务器发送数据包,当然越快越好,最好一次性全发出去。但是,发得太快,就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话,发得越快,丢得越多。
最理想的状态是,在线路允许的情况下,达到最高速率。但是我们怎么知道,对方线路的理想速率是多少呢?答案就是慢慢试。
TCP 协议为了做到效率与可靠性的统一,设计了一个慢启动(slow start)机制。开始的时候,发送得较慢,然后根据丢包的情况,调整速率:如果不丢包,就加快发送速度;如果丢包,就降低发送速度。
例如刚开始通信的时候,发送方一次性发送10个数据包,即"发送窗口"的大小为10。然后停下来,等待接收方的确认,再继续发送。
其中的发送窗口大小就是Window size而确认消息就是ACK
ACK 携带两个信息:
发送方有了这两个信息,再加上自己已经发出的数据包的最新编号,就会推测出接收方大概的接收速度,从而降低或增加发送速率。
由于 TCP 通信是双向的,所以双方都需要发送 ACK。两方的窗口大小,很可能是不一样的。
我们通过一个实例来看一看其中的Seq和ACK变化:
主要观察每次通信间Seq,ACK的变化和ACK-Len的关系。
TCP Flags
TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。
需要注意的点:
TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK标志必须为1
SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
TCP三次握手,四次分手
吼啦,基础信息都了解了一些了,接下我们就来看看经典的三次握手和四次分手吧!
下面有两个对照图,可能在了解后面内容需要不时的对照翻看,建议可以手动画一画,非常有帮助哦(●>∀<●)
以下是TCP建立连接,数据传输,断连接的对照图:
TCP协议状态机对照图:
三次握手
为什么建立连接要进行3次握手呢?
先来看看这三次握手TCP干了些啥,每个步骤可以对照上面对照图进行分析。
下面从TCP首部字段的变化来了解其中的意义:
Sequence Number
我们可以发现三次握手,主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN(同步序号),全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个序号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
关于ISN即seq的初始化,我们前面在介绍seq的时候我们说过这个初始数值为一个随机数。
为什么不能hard code 呢?
用一个例子来解释:
如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。这样就全乱了。所以需要一个不重复的随机数来作为初始值。
Acknowledgment Number
从设置Acknowledgment Number的值我们可以发现:为了保证服务端能收接受到客户端的信息并能做出正确的应答而进行前两次(第一次和第二次)握手,为了保证客户端能够接收到服务端的信息并能做出正确的应答而进行后两次(第二次和第三次)握手。
其实前两次握手就可以建立连接,但是为什么要进行第三次握手呢?
考虑这样一种场景:
client端发送连接请求,但是由于请求报文丢失没有收到确认报文,于是client再次发送连接请求,这次正常进行了连接,传输数据,断开连接 。
如果client第一次发送的报文是因为某个网络结点长时间的滞留了,在第二次连接断开后发送到了server端,server端会如何处理呢?对比下面两种情况:
那么可以将第三次握手理解为,防止server端因为一直等待造成的资源浪费的措施。
番外篇
另一种解释三次握手,可以开阔一下思路:
四次分手
客户端和服务器通过三次握手建立连接后,开始传输数据,数据传输完毕后。客户端想要断开连接,这里就要进行四次分手。
老套路,先看四次分手聊了些什么,对照状态机当然是少不了(其中的seq和ACK数值使用对照图内容):
seq = x + 2
和ACK = y + 1
,将连接释放报文首部终止控制位FIN置为1。此时,client进入FIN_WAIT_1(终止等待状态1)状态,等待server确认。ACK = x + 3
(为seq加1)。server进入CLOSE_WAIT(关闭等待)状态。此时TCP连接处于半关闭状态,即client已经没有数据要发送了,但是server发送数据client任然接受,也就是server到client方向连接还没有关闭。client收到来自server的确认报文ACK后,就进入FIN_WAIT 2(终止等待2)状态,等待server发送连接释放报文seq = y + 1
和上次发送过的ACK = x + 3
。然后server进入LAST_WAIT(最后确认状态)状态,等待client确认。ACK = y + 2
,seq = x + 3
然后进入TIME_WAIT状态。server收到client确认报文段以后,就关闭连接CLOSED。此时,client等待2MSL后依然没有收到回复,则证明server端已正常关闭,那么,client也关闭连接CLOSED。这里我们要注意client进入TIME_WAIT后会等待2MSL后才会进入CLOSED状态。
什么是MSL?
MSL叫做最长报文寿命(Maxximum Segment Lifetime),RFC793建议设置为2分钟,Linux设置成了30s,TCP允许不同实现根据情况设置更小的时间。
为什么要等待2MSL?
要等待2MSL有两个原因:
1.保证client发送的最后一个ACK报文能够到达server端。
考虑这样一个场景:
如果client发送的最后一个ACK报文丢失了,我们看看client等待2MSL和不等待2MSL的区别
2.有足够的时间让这个连接不会跟后面的连接混在一起
防止像之前提到因为滞留在某个网络节点的报文出现,影响其他连接。所以在2MSL后本连接持续时间内产生的所有报文都会从网络中消失了。
Simultaneous Close
如果两边同时断连接(Simultaneous close),那就会就进入到CLOSING状态,然后到达TIME_WAIT状态。下图是双方同时断连接的示意图(你同样可以对照着TCP状态机看):
总结
当然以上这些内容只是简单的了解了TCP一些基础知识,但是为后面继续深入学习了解打下了基础。
通过以上的整理基本能够了解如下内容:
TCP是门古典的基础技术还有很多地方值得我去思考和学习,这仅仅是一个开始。
看到估计也累了,就到这里吧,梳理下来知识点不多,但是还是很有收获的,关于计算机网络这一块还有很多东西要去学习。
参考文章:
计算机网络
通俗大白话来理解TCP协议的三次握手和四次分手
TCP 协议简介
TCP/IP Reference
Understanding TCP Sequence and Acknowledgment Numbers
TCP 的那些事儿(上)
若文中有知识整理错误或遗漏的地方请务必指出,非常感谢。如果对你有一丢丢帮助或引起你的思考,可以点赞鼓励一下作者=^_^=
The text was updated successfully, but these errors were encountered: