TCP首部字段

image.png

  • 数据偏移:占 4 bit,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位不是字节而是 32 bit 字(4 字节为计算单位)
  • 保留:占 6 bit,保留为今后使用,但目前应置为 0
  • URG:紧急比特,当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快处理(相当于高优先级的数据)
  • ACK:确认比特,只有当ACK=1时确认号字段才有效;当ACK=0时确认号无效
  • PSH:推送比特(PuSH),接收 TCP 收到推送比特置 1 的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付
  • RST:复位比特(ReSeT),当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或者其它原因),必须先释放连接,然后再重新建立连接
  • SYN:同步比特,同步比特SYN置为1,就表示这是一个连接请求或者连接接受报文
  • FIN:终止比特(FINal),用来释放一个连接,当FIN为1的时候,表明此报文段的发送端的数据已经发送完了,要求释放运输连接
  • 窗口:占2个字节。由接收方写入,接收方根据自己缓存空间的大小确定对方的发送窗口的上限。在未收到接收方的确认消息之前,发送方可以连续发送的字节数是多少
  • 校验和:占2个字节。校验和检测范围包括首部和数据两个部分。在计算校验和时,需要在TCP报文段的前面加上12字节的伪首部。
  • 紧急指针:占2个字节。紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。
  • 选项字段:选项字段的长度是可变的。TCP只规定了一种选项,即最大报文段长度MSS(Maximum Segment Size)。MSS告诉对方TCP:“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节。”
  • 填充字段:与选项字段一起构成32bit。

TCP三次握手过程说一下?

在使用TCP进行通信之前需要进行三次握手来建立连接。三次握手的过程如下:
截屏2020-07-22 下午2.57.57.png
三次握手建立连接的过程:

  1. 客户端向服务器发送SYN请求连接报文,其中SYN置为1,同时随机生成序号(ISN)x。报文发送完毕后客户端由 CLOSED 状态转为 SYN_SEND 状态
  2. 服务端接收到客户端发送的SYN连接报文后,如果不同意建立连接,则直接发送rst报文终止通信。如果同意建立连接,则发回确认连接的报文(ACK)。在确认连接的报文中,SYN应该置为1,同时将确认号置为x+1,同时随机生成序列号(ISN)y+1。报文发送完毕后,服务器由 LINTEN 状态转为 SYN_RCVD 状态。
  3. 客户端(A)接收到服务器(B)发送的确认连接的报文后,向B发回一个确认连接的报文。在A发送的确认连接的报文中,将确认号置为y+1,序列号为x+1(传送数据时的第一个数据字节的序号)。客户端发送完ACK报文后,由 SYN_SEND 状态变为 ESTABLISHED 状态。服务端在接收到ACK报文后,由 SYN_RCVD 状态变为 ESTABLISH 状态。

在客户端和服务器都进入ESTABLISHED状态后,客户端和服务器之间就可以进行通信了。

TCP三次握手的目的是什么?

总的来说,三次握手是用来进行客户端和服务器间数据同步的,为之后建立可靠连接建立基础。TCP建立三次握手需要弄清楚通信双方的状态已经进行一些必要的协商,如:

  1. 服务器收到第一次握手的报文可以确定客户端的发送能力是OK的
  2. 客户端收到服务器发送的第二次握手的报文后可以确定服务器的接收能力和发送能力是OK的
  3. 服务器在收到客户器发送的第三次握手的报文后可以确定客户端的接收能力是OK的
  4. 在握手过程中双方可以协商报文的序列号,窗口大小等通信过程中需要的参数

TCP的三次握手中可以携带数据吗?

TCP三次握手中最后一次握手是可以携带数据的,但是也不是必须携带。
TCP规定,SYN报文段(即SYN=1的报文段)是不携带数据的,但是需要消耗一个序列号;ACK报文段可以携带数据,如果不携带数据的话就不消耗序列号。TCP的第一次握手和第二次握手都发送的是SYN报文段,所以都不携带数据。TCP的第三次握手是对服务器发送的SYN报文段的ACK报文段,所以可以在报文段中携带数据,但是需要消耗序列号。

能不能通过两次握手来建立TCP连接?

不能通过两次握手来建立连接,通过两次握手建立的连接是不可靠的,有时还会导致死锁和建立重复连接等问题。
使用两次握手建立连接过程中死锁发生的案例:客户端首先发送SYN报文建立连接,服务器接收到FIN报文后向客户端发送一个ACK进行确认,同时自己进入到 ESTABLISHED 状态,但是发送的这个ACK由于网络的问题没有到达客户端,此时服务器开始向客户端发送数据。在这种情况下,客户端要一直等到来自服务器对FIN报文的ACK报文才能进入到ESTABLISHED状态进行通信,而服务端一直在等待客户端发送ACK报文,这样服务端发送的数据会一直被重发,导致死锁问题。

使用两次握手建立连接过程中发生建立重复连接的问题:客户端先向服务器发送SYN连接报文请求建立连接,而此时由于网络拥塞导致客户端没有收到服务器的确认,此时客户端重新发送SYN报文,之后和服务器建立连接。在新SYN报文和服务器建立连接之后,旧的SYN报文到达了服务器,由于是两次握手,所以在客户端和服务器之间又建立了一条连接,导致客户端和服务器之间出现了多余的连接,浪费了服务器的资源。

TCP四次挥手过程说一下?

使用TCP协议进行通信的双方在希望结束通信的时候都可以发出断开连接请求来结束通信。在客户端与服务器双方断开连接的过程中,一共需要发送4个报文,俗称“四次挥手”。

四次挥手的过程如下图所示:
截屏2020-07-22 下午3.04.15.png
四次挥手的过程:

  1. 客户端发送FIN报文请求断开连接,同时指定序列号,报文发送完毕后客户端由 ESTABLISHED 状态变为 FIN_WAIT-1 状态。
  2. 服务器收到客户端的FIN报文后立即发送一个ACK报文,报文发送完毕后服务器由 ESTABLISHED状态变为 CLOSE-WAIT 状态。(此时不会立即关闭连接,而是通知应用进程即将要关闭连接)
  3. 客户端接收到服务器的ACK报文后,客户端由 FIN-WAIT1 状态变为 FIN-WAIT2 状态
  4. 服务器在应用进程处理完毕后(被动关闭)向客户端发送FIN报文,报文发送完毕后,服务器由 CLOSE-WAIT 状态变为 LAST-ACK 状态。此时客户端到服务器的单向连接已经关闭了。
  5. 客户端在接收到服务器发送的FIN报文后向服务器发送一个ACK报文,报文发送完毕后,客户端由 FIN-WAIT2 状态变为 TIME-WAIT状态。之后等待2MSL后关闭连接,进入到 CLOSED状态。
  6. 服务端在收到客户端的ACK后关闭连接,服务端由 LAST-ACK 状态变为 CLOSED 状态。

聊聊TCP四次挥手中的CLOSE-WAIT状态?

close-wait状态是服务器在接收到客户段的FIN断开连接的请求报文并向客户端发送ACK之后服务器的状态。
在该状态下,服务器会通知相应的应用进程TCP连接已经关闭,如果此时服务器需要发送数据给客户端是允许的,应用进程在处理完成后通知服务器,之后服务器发送FIN+ACK断开服务器与客户端的连接。
事实上,该状态下客户端到服务器的连接已经关闭了,但是服务器还可以向客户端发送数据

TIME-WAIT状态的作用是什么?

  1. 确保服务器收到客户端最后发送的ACK报文,让客户端和服务器正常进入到 CLOSED 状态。
  2. 浪费资源

如果没有TIME-WAIT状态会导致服务端无法进入到CLOSED状态。举个例子:客户端最后一次发送的ACK报文由于网络等问题在网络中丢失了,这样导致服务器没有接收到ACK报文。此时TCP的重传机制会导致服务器重新发送FIN报文来请求断开连接,而此时的客户端已经断开连接了,对服务器发送的报文的回复都是RST报文,所以服务器无法进入到CLOSED状态,连接也就无法释放,浪费资源。

TIME-WAIT状态的时间为什么是2MSL?

  1. 防止已经失效的建立连接的报文重新建立连接,浪费服务器资源
    • MSL(最长报文寿命 Maximum Segment Lifetime)是报文在网络中生存的最长时间,2MSL可以保证本次连接持续时间内所有在网络中报文都消失,这样可以保证下一个新的连接中不会产生旧的请求连接的报文段。
  2. 确保客户端发送的最后一个ACK报文能到达服务器
    • 当客户端最后发送的ACK报文在网络中丢失之后,服务器会再对客户端发送FIN报文来请求断开连接,如果时间为等待时间为2MSL的话,就能保证客户端接收到这个FIN报文,接着客户端继续发送确认,同时重启计时器,直到在计时器结束后还没有收到服务器发送的FIN报文,说明服务器已经成功接收到了客户端发送的ACK报文。

TCP中初始序列号是如何生成的?

TCP中的初始序列号也叫ISN固定码。为了使生成的初始序列号(ISN)具有不可预测性,使用TCP协议进行通信的双方的初始序列号都是随机生成的。
生成序列号采用的随机算法如下:
TCP建立连接和断开连接 - 图4

  • M是一个计时器,这个计时器每隔4毫秒加1。
  • F是一个Hash算法,根据源IP目的IP源端口目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出,可以使用MD5算法。

TCP的半连接队列和完全连接队列说一下?

Linux系统在实现TCP协议的时候使用到了半连接队列和连接队列,半连接队列也叫SYN队列,连接队列也叫accecpt队列。
具体的操作过程如下图所示:
image.png

  1. 服务器在收到SYN请求的时候就会去创建 request_sock 结构,并将其存储在syn队列中。
  2. 三次握手完成后(服务器收到了客户端发送的ACK),之前在半连接队列中的结构会进入到accept队列中。

当syn队列满后,Client端在多次重发SYN包得不到响应而返回connection time out错误;
当accept队列满后,client则会分别返回read timeout 或者 connection reset by peer

参考:https://www.jianshu.com/p/ff26312e67a9