上周终于面了知乎,结果跪了~一是基础还不怎么扎实,二是没有准备,原以为能在12月分面试呢,结果发完题过两天就发了面试通知,不过知乎的态度真的不错,面了一个半点,虽然大多数问的问题都能知道,但是平时都没深入了解,所以今天总结一下TCP协议.

TCP图示

TCP(Transmission Control Protocol)传输控制协议.

TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接.

TCP状态

上面图中白色部分是TCP协议的字段,可以看到TCP的flag有6个,着重介绍下:

  1. URG:紧急URG,当URG置为1时,发送应用进程就告诉发送方的TCO有紧急数据发送,于是发送方TCP就把紧急数据插入到本报文段数据的最前面.*(例如用户从键盘发出中断命令,如果不使用紧急数据那么这个命令就会放在TCO的缓存末尾,这样浪费很多时间)
  2. ACK:当ACK=1时Acknowledgment Number才有效.(仅在三次握手第一次握手时ACK=0,其他时刻ACK都为1)
  3. PSH:操作很少用到,当接受方TCP接受到PSH=1的报文段,就尽快的PUSH给接收应用进程,而不再等待整个缓存都填满后再向上交付.
  4. RST:当RST=1时说明发生了严重错误,必须释放连接,然后重新建立运输连接.
  5. SYN:连接建立时的同步信号,后面会说.
  6. FIN:释放连接,后面会说.

三次握手

  • 第一次握手: 客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里。

  • 第二次握手: 服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即X+1。

  • 第三次握手. 客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1

我们可以在wireshark上看一下包的传递,下面以解析百度首页为例:

可以清楚的看到前三个包就是三次握手的TCP包,所有包中有用信息都在info里,再来解释下其他字段含义:

  • Win:窗口字段明确指出现在允许对方发送的数据量(经常变化)
  • Len:暂时未知,TCP字段未有这个关键字?
  • MSS(Maximum Segment Size):最大报文段长度,即每个TCP报文段中的数据字段的最大长度.这里需要在握手的时候进行协商,双方都给出MSS,最后以最小MSS确定为最终的MSS.IP数据报最大传输单位为MTU(Maximum Transmission Unit,Effect of short board),对于大多数使用以太网的局域网来说,MTU=1500。MSS往往基于MTU计算出来,通常MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460,这里我们看到服务器MSS=1460,而客户端的MSS=1440,所以最终为1440.
  • SACK_PERM:选择确认字段,如果中间缺少包而其他包都已经接收,那么直接传送缺少包.

第三次握手和其他数据传输包没有区别,原因是这个包是为了改变服务器状态,使服务器从半连接状态转换为全连接状态.

四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

  1. 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
  2. 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
  3. 服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
  4. 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。

在来看看百度的例子:

其实第2,4部和普通的数据传输包没有区别,关键是第1,3个FIN包,它们告诉对方自己将不传送信息,只接受信息.所以TCP的四次挥手可以看成是两个二次握手

为什么采用3次握手而不是2次握手?

如果两次握手的话,客户端有可能因为网络阻塞等原因会发送多个请求报文,这时服务器就会建立连接,浪费掉许多服务器的资源.

为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

为什么在四次挥手中A在TIME-WAIT状态必须等待2MSL的时间?

  1. 为了保证A发送的最后一个ACK报文能到达B.
  2. 防止"已失效的连接请求报文段",2MSL过后网络中没有此次连接的报文,可以进行下一个连接.

最后TCP有限状态机:

参考资料