TCP协议详解

Posted JavaEdge.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP协议详解相关的知识,希望对你有一定的参考价值。

UDP基本包括了传输层所必须的端口字段。它相信“网之初,性本善,不丢包,不乱序”。

后来呢,我们都慢慢长大,了解了社会的残酷,变得复杂而成熟,就像TCP协议一样。它之所以这么复杂,那是因为它秉承的是“性恶论”。它天然认为网络环境是恶劣的,丢包、乱序、重传,拥塞都是常有的事情,一言不合就可能送达不了,因而要从算法层面来保证可靠性。

TCP包头格式

  • TCP头

    源端口号和目标端口号和UDP是一样的。如果没有这两个端口号。数据就不知道应该发给哪个应用。

包的序号。为什么要给包编号呢?
为了解决乱序的问题。不编好号怎么确认哪个应该先来,哪个应该后到呢。编号是为了解决乱序问题。

确认序号。
发出去的包应该有确认。若没有收到就应该重发,直到送达,以达到不丢包的目的。

TCP是靠谱的协议,但不代表它所处的网络环境很好。
IP层来看,如果网络状况的确差,无任何可靠性保证,即使是IP的上一层TCP也无能为力,能做的只是更努力,不断重传,通过各种算法尽量保证。
即对于TCP,IP层你丢不丢包,我管不着,但在我TCP层,会尽力保证可靠性。

一些状态位,例如:

  • SYN
    发起一个连接
  • ACK
    回复
  • RST
    重新连接
  • FIN
    结束连接

TCP是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变更。

窗口大小。
TCP要做流量控制,通信双方各声明一个窗口,标识自己当前能够的处理能力,别发送太快或太慢。
拥塞控制,对于真正的通路堵车不堵车,它无能为力,唯一能做的就是控制自己,也即控制发送的速度。

TCP的三次握手

首先要先建立一个连接,TCP的连接建立,常称为三次握手。

  • A:您好,我是A
  • B:您好A,我是B
  • A:您好B

也常称为“请求->应答->应答之应答”的三个回合。

为什么要三次,两次不够吗?
我们生活里两个人打招呼,一来一回就够了呀,那既然为了可靠,为啥不是四次?

假设这个通路是非常不可靠的,A要发起一个连接,当发了第一个请求,无响应,会有很多的可能性,比如:

  • 第一个请求包丢了
  • 没有丢,但是绕了弯路,超时了
  • B没有响应,不想和我连接

A不能确认结果,于是再发发发。终于有个请求包到了B,但请求包到了B这件事,目前A还是不知道,所以A可能再发。

B收到请求包,就知道了A的存在,并且知道A要和它建立连接。
若B

  • 不情愿建立连接,则A会重试一阵后放弃,连接建立失败,没有问题
  • 乐意建立连接,则会发送应答包给A

对于B,这个应答包也是不知道能不能到达A。这时B自然也不能认为连接是建立好了,因为应答包:

  • 会丢
  • 会绕弯路
  • A挂了

都可能。而且这时B还能碰到一个诡异现象:A和B原来建立了连接,简单通信后,结束了连接。还记得吧,A建立连接时,请求包可能重复发几次,有的请求包绕了一大圈又回来了,B会认为这也是一个正常的的请求的话,因此建立了连接,可以想象,这个连接不会进行下去,也没有个终结的时候,纯属单相思。
所以两次握手不够。

B发送的应答可能会发送多次,但只要一次到达A,A就认为连接已建立,因为对于A,他的消息有去有回。A会给B发送应答之应答,而B也在等这个消息,才能确认连接的建立,只有等到了这个消息,对于B来讲,才算它的消息有去有回。

当然A发给B的应答之应答也可能:

  • 丢了
  • 绕路
  • B挂了

看起来应该还有个应答的应答的应答,但这样下去就没底了。所以四次握手是可以的,四十次都可以,关键四百次你也不能保证就真的可靠了。
所以只要保证:双方的消息都有去有回即可。

实际上大部分情况下,A和B建立连接后,A会马上发送数据,一旦A发送数据,则很多问题都得到解决。
例如A发给B的应答丢了,当A后续发送的数据到达时,B可认为该连接已建立,或B就是挂了,A发送的数据,会报错,说明B不可达,A就知道B有异常。

当然你可以说A比较坏,就是不发数据,建立连接后一直空着。可以开启keepalive机制,即使没有真实数据包,也有探活包。

作为服务端B的开发人员,对于A这种长时间不发包的客户端,可主动关闭,从而空出资源响应其它客户端。

三次握手还为了解决

TCP包的序号问题

A要告诉B,我这面发起的包的序号起始是从哪个号开始的,B同样也要告诉A,B发起的包的序号起始是从哪个号开始的。
为什么序号不能都从1开始?
这样往往会出现冲突。

例如,A连上B后,发了1、2、3三包。
发送3时,中间丢了或绕路了,于是重发。
后来A掉线了,重连上B后,序号又从1开始,然后发送2,但没想过发送3,但上次绕路的那个3又回来了,发给了B,B自然认为,这就是下一个包,于是发生错误!

所以每个连接都要有不同序号。
序号的起始序号随着时间变化,可看成一个32位的计数器,每4ms加一。
稍稍计算一下,若重复,需4h+,那个绕路的包也早就没了,因为IP包头里有个TTL,生存时间。

最后双方终于成功建立了连接。为维护该连接,双方都要维护一个状态机,在连接建立的过程中,双方的状态变化时序图就像:

  • 起初,客户端、服务端处CLOSED状态
  • 先是服务端主动监听某个端口,处于LISTEN状态。
  • 然后客户端主动发起连接SYN,之后处于SYN-SENT状态
  • 服务端收到发起的连接,返回SYN,并且ACK客户端的SYN,之后处于SYN-RCVD状态
  • 客户端收到服务端发送的SYN和ACK之后,发送ACK的ACK,之后处于ESTABLISHED状态,因为它一发一收成功了
  • 服务端收到ACK的ACK之后,处于ESTABLISHED状态,因为它也一发一收

TCP四次挥手

好说好散,四次挥手。

  • A:B啊,我不想玩了
  • B:哦,你不想玩了啊,我知道了

这个时候,还只是A不想玩了,即A不会再发数据,但B能不能在ACK时,直接关闭呢?当然不可以,很可能A是发完了最后的数据就准备不玩了,但是B还没做完自己的事情,还是可发送数据,所以称为半关闭状态。

这时A可选择:

  • 不再接收数据
  • 或最后再接收一段数据,等待B也主动关闭

B:A啊,好吧,我也不玩了,拜拜
A:好的,拜拜

这样整个连接就关闭了。这是和平分手。

A开始说“不玩了”,B说“知道了”,这个没问题,因为在此之前,双方还处于合作的状态。
若A说“不玩了”,没有收到回复,则A会重发“不玩了”。但这个回合结束后,可能出现异常情况,因为已有一方率先撕破脸:

  • A说完“不玩了”后,直接跑路,就有问题,因为B还没发起结束,而若A跑路,B就算发起结束,也得不到回答,B就不知道该怎么办了
  • A说完“不玩了”,B直接跑路,也有问题,因为A不知道B是还有事情要处理,还是过一会儿会发送结束回来

解决这些问题?
TCP协议专门设计了几个状态来处理这些问题。我们来看断开连接的时候的状态时序图

断开时可见:

  • 当A说“不玩了”,就进入FIN_WAIT_1状态
  • B收到“A不玩”消息后,发送知道了,进入CLOSE_WAIT状态
  • A收到“B说知道了”,就进入FIN_WAIT_2状态。若此时B直接跑路,则A将永远在这个状态。TCP协议里面并没有对这个状态的处理,但Linux有,可以调整tcp_fin_timeout参数,设置一个超时时间。
  • 若B没有跑路,发送“B也不玩了”请求到达A时
  • A发送“知道B也不玩了”ACK后,从FIN_WAIT_2状态结束。按理说,A现在可以跑路了,但最后的这个ACK万一B收不到呢?则B会重新发一个“B不玩了”,这时若A已跑路,B就再也收不到ACK,所以TCP协议要求A最后等待一段时间TIME_WAIT,这个时间要足够长,长到如果B没收到ACK,“B说不玩了”会重发的,A会重新发一个ACK并且足够时间到达B。

A直接跑路还有一个问题是,A的端口就直接空出来了,但B不知道,B原来发过的很多包很可能还在路上。此时若A的端口被一个新应用占用,这个新应用会收到上个连接中B发过来的包,虽然序列号是重新生成的,但这里要上一个双保险,防止产生混乱,因而也需要等足够长的时间,等到原来B发送的所有的包都死翘翘,再空出端口来。

等待的时间设为2MSL,MSL:Maximum Segment Lifetime,报文最大生存时间,是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为TCP报文基于是IP协议的,而IP头中有一个TTL域,是IP数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。协议规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

若B超过2MSL,依然没有收到它发的FIN的ACK,怎么办?
按TCP原理,B会重发FIN,这时A再收到这个包后,A就表示,我已经在这里等了这么长时间了,仁至义尽,之后的我也不认了,于是就直接发送RST,B就知道A早跑了。

TCP状态机

将连接建立和连接断开的两个时序状态图综合起来,就是这个著名的TCP的状态机。学习的时候比较建议将这个状态机和时序状态机对照着看,不然容易晕。

阿拉伯数字序号,是连接过程中的顺序,而大写中文数字的序号,是连接断开过程中的顺序。

  • 加粗的实线是客户端A的状态变迁
  • 加粗的虚线是服务端B的状态变迁

以上是关于TCP协议详解的主要内容,如果未能解决你的问题,请参考以下文章

TCP协议详解

TCP协议详解

TCP/IP详解学习笔记

TCP协议---TCP协议详解

TCP协议的超时详解

TCP/IP协议详解