网络协议概述——TCP,5分钟快速了解

目录

         一、何为TCP协议

二、对于TCP协议来说,UDP它与UDP协议不同之处在于:

三、TCP首部各个字段的作用分别是什么

四、TCP的连接建立

1、关于TCP连接的建立,首先要清楚TCP的连接特点

2、TCP连接建立中的三次握手(先上图:)

3、详细过程

4、关于三次握手

5、为什么不用两次握手呢

五、TCP连接的释放

1、大致过程示意图

 2、过程详细说明

3、为什么客户端最后要等待 2*MSL时间呢

4、保活计时器


一、何为TCP协议

TCP协议,大名叫:传输控制协议。看名字就知道,它是负责对数据报文的传输进行一定控制作用的。简单看看它工作的地方:

                                                   

        由图可知,它和它的好哥们UDP工作在运输层(也称传输层)。这一层当然是至关重要的,所谓运输层,它主要是提供端到端的接口,为它上面的应用层提供通信服务,属于是面向通信的最高部分。当我们网络中两台边缘主机要进行通信时,必须就要用到TCP/IP协议栈的运输层。关于传输层的知识其它文章会详细讲解,这里就不再过多的赘述了。


二、对于TCP协议来说,UDP它与UDP协议不同之处在于:

1、TCP提供的是面向连接的服务。

        何为面向连接的服务?面向连接的服务与无连接的服务区别就在于进行通信前是否需要提前建立好连接。对于TCP协议来说,既然它属于是面向连接的服务,所以使用TCP协议进行通信前,就必须要事先建立好连接,在传输完成之后,还要释放所建立的连接。这就好比应用进程之间的通信好像是在“打电话”,通话之前需要先拨号,建立通话连接;通话结束后,挂断电话,所连接的通信链路就被断开。

2、提供的是全双工通信。

        全双工通信,就是指通信的任意一端既可以接收数据,也可以发送数据,且允许同时进行。这一点是十分重要的,就好比我们打电话,要是只允许电话两头的人都只能听完再说,或者说完再听,这岂不是很难受……所以TCP协议就很好的满足了这一点,它在建立连接的两端都设置有发送缓存和接收缓存,作用就是临时存放双向通信的数据。接收端所受到的数据都要先放在接收缓存,所以上层应用进程也是对缓存中的数据进行读取。但是设置缓存的好处并不止这一点,可以思考还有什么作用?

3、面向字节流。

       “字节”都能理解,“流”是啥子?所谓“流”,就是指流入到进程或进程流出的字节序列。对于我们的TCP协议来说,应用进程给到它的数据是一块一块的,但是我TCP只负责百分百将所有数据完好的送到对面进程,并不会管数据到底有几块,而是把所有数据看成一连串的无结构的字节流,然后给每个字节打上序列号,再送走。

4、提供可靠的交付。

       可靠的交付,是TCP相对于UDP协议来说,最大的一个优势。所谓可靠的交付,就是通过TCP协议控制的数据报文传输,整个过程是无差错、不丢失、不重复的、并且按序到达的。

TCP与UDP的其它不同之处见下图:

TCP与UDP的差异对比

既然我们看到TCP相对于UDP的优点这么多,那么都是怎样实现的呢?实际上,TCP协议的全部功能,都体现在它的首部各个字段的作用上,所以接下来就来研究TCP报文的首部字段是怎么回事。

注意看这是UDP的首部报文格式:

 再对比TCP的首部报文格式:

 可以明显看出,TCP协议的首部报文明显比UDP协议字段格式要复杂得多,这也正是为什么TCP协议能够做到UDP协议做不到的很多功能。


三、TCP首部各个字段的作用分别是什么

1、源端口和目的端口:这两个字段分别占了2个字节。顾名思义,就是标记了报文发送方以及接收方的这条TCP通信端口。

2、序号:序号字段占4个字节。因为TCP是面向字节流的,所以在一个TCP连接中传送的字节流中的每一个字节都要按顺序编号,整个要传送的字节流的起始序号必须在连接建立时设置。且首部中的序号字段值是指的是本报文段所发送的数据的第一个字节的序号,比如说一段序列号为100的报文,它一次传输200字节的数据,则它的下一次报文的序号就应该等于400。

3、确认号:同样也是占了4个字节。确认号顾名思义也就是对收到的报文进确认,它主要是让通信对方知道自己对哪一个报文进行的确认,所以通过序号来区别。但是它的数值并不是确认的那段报文的序列号,而是返回的是期望下一次收到的报文的第一个字节的序号。挺起来不好理解,比如发送方发送100字节的数据给接收方,第一个字节序号等于200,那么接收方回给发送方的报文中,确认号就等于发送方下一次传送100字节的第一个字节的序号,即301。

4、数据偏移:这个字段只占了1/2个字节,即4位。它指明了TCP报文段的数据起始处到TCP报文段的起始处的距离,实际上就是TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。但应注意,“数据偏移”的单位是32位字(即以4字节的字为计算单位)。由于4位二进制数能表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节)。

5、保留:保留字段只占6位。通常置为0,留作以后使用。

然后就是6个控制位,用于标识该报文段的一些性质

6、URG:紧急URG(URGent)。当URG等于1的时候,仅表明紧急指针字段此时有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。

当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

7、ACK:确认ACK(ACKnowledgment)。仅当ACK等于1时确认字段才有效。当ACK等于0时,确认号是无效的。TCP规定,在连接建立后,所以TCP通信中的报文ACK都必须置为1。

8、PSH:推送PSH(PuSH)。当两个应用进程双方进行交互通信时,有时一段的进程希望在键入一个指令后马上得对方的回应,在这种情况下,TCP就可以使用push操作。即发送方将PSH置为1,并且立即创建一个报文发送出去,接受端接收到以后,发现PSH被置为1,所以就将此报文尽快地交付給进程,而不再等待缓冲区填满后再等进程来取数据。

尽管进程可以使用这个操作,但是很少有进程使用。

9、RST:复位RST(ReSet)。当RST等于1的时候,表示TCP连接出现了严重差错,此时必须释放该条连接,然后再重新建立运输连接。还可以将RST置为1用来拒绝一个非法的报文段或者是拒绝打开一个连接。所以它又称为重置位或重建位。

10、SYN:同步SYN(SYNchronization)。在建立连接时用于同步序列号。当SYN等于1而ACK等于0的时候,表明这是一个连接请求报文,如果对方同意建立连接,那么在回给发送方的响应报文中SYN以及ACK置为1。所以,SYN等于1就表示这是一个连接请求或者连接同意报文。

11、FIN:终止FIN(FINish)。用于释放一个连接。当FIN置为1的时候,表示发送此报文的一端数据已全部发送完毕,请求断开运输连接。

12、窗口:占2个字节。窗口指的是发送本报文段的一方的接受窗口,而不是自己的发送窗口。它表明了接受方从本报文段的确认号算起,目前可以接受的发送方发送的数据量大小(以字节为单位),这是因为接受方的缓存空间是有限的。简单来说,目的就是控制对方的发送速率,不要超过了自己的接收能力。总之,窗口值作为接收方让发送方设置自己发送窗口大小的依据。窗口字段值指明了接收方允许发送方发送的数据量,且这个值是动态变化的。

13、检验和:此字段占2个字节。检验和字段检验的范围包括首部以及数据这两个部分。同UDP一样,在计算检验和时,要在报文段前面加上12个字节的伪首部,伪首部的格式UDP中的格式是一样的。如下图:

                       

但是应该把伪首部第四个字段的17改为6,因为TCP的协议号为6,把第五字段中的UDP长度改为TCP长度。接受方收到此报文段后,仍要加上这个伪首部来计算校验和。若使用ipv6,则相应的伪首部也要改变。

14、紧急指针:占了2个字节。前面讲到过,紧急指针只有当URG等于1的时候才有效,它指出的是本报文紧急数据的字节数,而紧急数据之后就是普通数据,所以紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据处理完成后,TCO就告诉应用进程恢复到正常操作。特别注意的是,当窗口值等于0的时候,紧急指针也会发挥作用,即也能发送紧急数据。

15、选项:这个字段长度是可变的,最长的时候可以达到40个字节。当没有使用“选项”时,TCP首部长度只用固定20个字节。

16、填充:这个字段仅仅是为了使整个TCP首部长度是4字节的整数倍。

对于选项字段,这里再特别指出:TCP最初只规定了一种选项,即最大报文段长度MSS(Maximum Segment Szie)。MSS是每一个TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是整个TCP报文段的最大长度,而是“TCP报文段长度减去TCP首部长度”。我们知道,TCP报文段的数据部分,至少要加上40字节的首部(TCP首部20字节和IP首部20字节,这里还没有考虑首部中的可选部分)才能组装成一个IP数据报。若选择较小的MSS长度,网络的利用率就降低。 因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。然而最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。S若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节。后来又增加了几个选项如窗口扩大选项、时间戳选项等。窗口扩大选项是为了扩大窗口。我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2^(16+14)-1=2^30-1。

时间戳选项占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。主要作用是用来计算往返时间RTT以及用于处理TCP序号超过2^32的情况,这又称为防止序号绕回PAWS。


四、TCP的连接建立

1、关于TCP连接的建立,首先要清楚TCP的连接特点

        每一条TCP的连接有两个端点。我们习惯上称TCP的连接双方客户端和服务器,但是实际上作为TCP连接的两个端点,既不是主机、IP地址,也不是应用进程和协议端口,而是一个新名词“套接字”。每条TCP连接的端点就叫做套接字或者插口。何为套接字?根据RFC973的定义,端口号拼接到IP地址就构成了套接字,即套接字是由IP地址+端口号组成的。

即总有: 套接字=(IP地址:端口号)

所以,两个通信终端的套接字唯一地标识了一条TCP连接,下面即是TCP与套接字连接示意图:

 同时要注意,同一个IP地址可以有多个不同的TCP连接,同一个端口号也可以出现在多个不同TCP连接中。

2、TCP连接建立中的三次握手(先上图:)

3、详细过程

刚开始, 客户端和服务器都处于 CLOSE 状态。
此时,,客户端向服务器主动发出连接请求,服务器被动接受连接请求。。。。。

1)TCP服务器进程先创建传输控制块TCB, 时刻准备接受客户端进程的连接请求,,此时服务器就进入了 LISTEN(监听)状态。

2)TCP客户端进程也是先创建传输控制块TCB,,然后向服务器发出连接请求报文。此时报文首部中的同步标志位SYN=1,,同时选择一个初始序列号 seq = x,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定, SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。

3)TCP服务器收到请求报文后, 如果同意连接,,则发出确认报文。ACK=1, SYN=1, 确认序号ack=x+1,,同时也要为自己初始化一个序列号 seq = y,此时,,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
4)TCP客户端进程收到确认后还要向服务器给出确认。确认报文的ACK=1,确认序号是 y+1,自己的序列号是 seq=x+1。

5)此后,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

4、关于三次握手

这实际上是在一次握手中交换了三次报文,并不是进行了三次握手。但是结合日常,两个人见面时互相问好握手,上下摇晃三次,所以用“三次握手”来形容TCP连接建立是比较恰当的。

5、为什么不用两次握手呢

实际上,看似两次握手简单,但是这样会导致一些问题。比如A主动向B发起连接,A率先发起第一次连接请求, 但是由于一些问题,导致第一次请求消息滞留在半路未能及时到达B端,所以A未能受到B的确认报文,此后A又发起第二次连接请求,到达B端后,B端回复连接确认报文,并开始准备接收A端的数据;当数据传输完毕后,AB之间断开这条连接,而恰巧过后A第一发出的请求报文到达了B端,B段就回复确认报文,误认为A端是在请求连接,然后又打开连接通道,等待A端发送数据,但是A端此时已经没有数据发送,所以B端就会一直等待,导致资源浪费;这就是基于两次握手导致的问题,所以才有三次握手,即B端回复确认报文后,还要等待A端的确认报文发过来以后,才正式确认建立连接。


五、TCP连接的释放

1、大致过程示意图

 2、过程详细说明

此时客户端和服务器都是处于ESTABLISHED状态,然后客户端主动断开连接,服务器被动断开连接.

1) 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

2)服务器收到连接释放报文,发出确认报文,ACK=1,确认序号为 u+1,并且带上自己的序列号seq=v,此时服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

3)客户端收到服务器的确认请求后,此时客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最终数据)

4) 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,确认序号为v+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,确认序号为w+1,而自己的序列号是u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

3、为什么客户端最后要等待 2*MSL时间呢

       这样的设计有两个用处:第一保证客户端最后发送的ACK报文能够到达服务器。如果不等待这个时间,而是直接释放连接,导致服务器不能收到ACK报文,那么服务器就不能正常进入CLOSED状态;如果等待的2*MSL时间内,B服务器没有收到ACK报文,那么服务器就会发送超时重传FIN+ACK报文,客户端收到后就会重发ACK报文,确定服务器能够收到。第二个作用就是避免前面提到的滞留请求报文问题,在等待的2*MSL时间内,能确保所有这次TCP连接交互的报文从网络中消失,确保下一次新的连接中不会出现旧的请求报文。

4、保活计时器

实际上,除了时间等待计时器,TCP还设有保活计时器。顾名思义,就是确保TCP连接都是“活着的”,因为实际情况中,免不了客户端建立连接后出现客户端故障现象,此时服务器收不到客户端的数据,也不可能一直等待,浪费服务器资源。所以保活计时器就起作用了,服务器每次收到数据,就会重置保活计时器,通常时间为2个小时。若两个小时内服务器没有收到客户端的数据,就发送一个探测报文,之后每隔75s发送一次,连续发送超过10次后,依旧没有收到客户端响应,服务器就认为客户端故障,并释放此次连接。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>