本文是对小林的图解网络的总结
TCP简介
TCP作为一个传输层协议,是一个面向连接的字节流,为应用层提供端到端的传输服务。和UDP不同的是,TCP提供的是可靠的面向连接传输服务,并且提供了流量控制等功能。
UDP提供的是无连接的不可靠服务。
TCP提供了全双工的通信方式。
TCP头部
首先说下TCP的头部,TCP头部是实现TCP协议的重要部分。
如上图所示,TCP头部主要包括以下信息:
1、源端口号 (16位):
数据包的发送方端口
2、目标端口号 (16位)
数据包的接收方端口
3、序列号 seq(32位)
在请求连接的时候操作系统会分配一个32位的数作为序列号,用来标识一个数据包在发送中的位置。
TCP为应用层数据中的每个字节都分配了一个seq号,TCP就是利用seq来实现的可靠传输。
TCP中的seq指的是TCP数据包中应用层数据的第一个字节对应的序列号。
4、确认应答号 ack(32位)
表示发送端中seq在ack之前的所有字节都已经被接收方接收了,接收方下一个希望接收的seq是ack。
5、 4个主要标识位
1、SYN
SYN = 1,代表这个数据包是客户端和服务器之间连接数据包。
2、ACK
ACK = 1,代表这个数据包是一个答复包,用于确认收到的数据包。
3、FIN
FIN = 1,说明这是一个单方面结束连接的数据包
4、RST
RST = 1,说明TCP连接出现异常强制断开连接。
TCP三次握手
TCP是一个面向连接的传输服务,在传输之前,需要先建立连接。
在握手之前,服务器必须开启,并且监听某个端口。
然后客户端开始向服务器发送连接请求。
第一次握手
第一次握手是由客户端向服务器发送的SYN数据包。
SYN数据包的头部有以下特点:
1、SYN标志位
SYN标志位为1,标志着客户端想要和服务器建立连接。
2、序列号 seq
客户端初始化一个数作为序列号 x ,序列号标识着数据包在客户端中发送的所有数据包中的位置。
SYN数据包不包含任何应用层数据。
客户端发送完SYN数据包后,客户端就处于SYN-SENT状态。
第二次握手
第二次握手是服务器在接收到客户端的SYN数据包后发送给客户端的回应数据包。
第二次握手的数据包有以下特点:
1、seq
服务器也会初始化一个数作为seq = y,序列号代表着数据包在服务器在这个连接中发送的所有数据包的位置。
2、SYN标志位
SYN = 1,标志着是服务器对于客户端建立连接的回应数据包。
3、ACK标志位
ACK = 1,标志着有一个数据包被接收了,到底是对哪个数据包的确认,数据包的序列号信息存储在ack字段中。
4、ack = x + 1
ack字段存储的是确认回答的数据包的序列号x+1,代表着这个序列号小于x+1 的数据包已经被接收了。
当服务器接收到客户端的SYN数据包后,会返回一个SYN数据包。
服务器首先初始化一个数作为SYN的序列号seq : y,然后将SYN标志位和ACK标志位设为1,接着将 确认应答号ack设置为x+1。
然后将SYN数据包发送给客户端,服务器SYN包仍然不携带应用层数据。
发送完SYN数据包后,服务器进入SEND-RCVD状态。
具体的做法就是服务器中每个端口对应的有一个半连接队列,会将对应的ack、客户端ip地址、端口号等封装成节点加入到半连接队列中
SYN攻击就是利用半连接队列来做手脚的,SYN攻击就是利用不同的ip地址来发送SYN包,让其不断进入服务器的半连接队列,让半连接队列占满,不能为正常用户工作。
第三次握手
客户端收到服务器的SYN数据包后,会发送一个数据包来应答。
数据包有以下特点:
1、ACK标志位
ACK = 1,标志着是对服务器SYN数据包的确认回答。
2、ack = y + 1
ack字段存储的是y+1。表示序列号小于y+1的数据包已经被接收了。
3、seq = x + 1
序列号为x+1,
客户端在第三次握手的时候,就可以携带应用层数据了。在发送完第三次握手数据包后,客户端就进入ESTABLISH状态。
当服务器接收到客户端的第三次握手数据包后,也会进入ESTABLISH状态。
当发送完三次握手数据包后,服务器和客户端都进入了ESTABLISH状态,也就代表双方正式建立了连接。
为什么需要三次握手而不是两次或者四次
两次握手出现的问题:
如果是两次握手的话,当服务器收到客户端发来的连接请求后,马上就要为客户端初始化内存,建立连接。 当出现以下异常情况的话,会造成资源浪费。
1、防止出现历史连接
TCP有超时重传机制,就是当一个数据报发送完之后,如果超过一段时间没有接收到对应的确认应答数据包,就会重新发送一次。
我们假设这样的情况,客户端第一次发送了一个SYN数据包1,seq为1,选择了一个耗费时间比较长的路由,导致过了超时时间还没有发送到服务器。这个时候客户端会重新发送一个SYN数据包2,seq为2,就是在SYN数据包2发送过程中,之前的SYN数据包1到达了服务器,这时服务器会发送一个SYN确认包3,对应的ack = 2。当客户端接收到SYN确认包3的时候,会比较ack和当前seq是否一样,这时客户端由于超时,已经发送了一个SYN数据包2,客户端中的seq已经增加到了3,不等于SYN确认包3中的ack 2,所以TCP会判定这是一个历史连接,就会发送一个RST标志位为1,seq = 2的数据包,RST的做法是将历史连接对应的节点从服务器中的半连接队列中移除。
如果是两次握手的话,对于失效连接是无法处理的,没有办法发送RST数据包了。
2、避免资源浪费
我们再假设这一种情况,也是数据包超时了,但是这时客户端没有重新发送,而是关闭了,当数据包传入到服务器的时候,服务器会为其创建连接,但是这时客户端已经关闭了。这就白白浪费了服务器的资源。
服务器中同一个端口的多个socket利用客户端IP和客户端端口号来唯一标识一个socket。
因为三次握手就可以满足建立连接的条件了,所以不需要四次握手了。
四次挥手
TCP的建立和释放都是由客户端发起的。
1、第一次挥手
由客户端发起断开请求,断开的是客户端向服务器写数据的方向连接,服务器还是能继续向客户端写入数据的,FIN数据包中有以下特点:
FIN标志位
FIN=1,表示这是一个断开连接的数据包
seq = p
发送完FIN数据包后,客户端进入FIN_WAIT_1状态。
2、第二次挥手
当服务器接收到客户端的FIN数据包后,会返回确认应答包。数据包有以下特点:
ACK标志位
ack = 1,标志着是确认应答包
ack
ack = p + 1,表示序列号为finClientSeq的数据包已经被接收
seq = a
第二次挥手后,服务器进入CLOSED_WAIT状态
第三次挥手
第三次挥手是服务器向客户端释放连接发送的FIN数据包,有以下特点
1、FIN标志位 = 1
2、seq = q
发送完之后,服务器进入LAST_ACK,表示这时服务端进入最后的应答状态,等待客户端的确认回答。
第四次挥手
第四次挥手是客户端向服务器发送的数据包,有以下特点:
1、ACK标志位 = 1
2、ack = q+1
3、seq = b
发送完之后,客户端进入TIME_WAIT状态
如果服务器接收到客户端发来的数据包就会进入CLOSED状态。
客户端在等待2MSL后,也会进入CLOSED状态。
为什么四次挥手
TCP是一个全双工通信协议。客户端可以向服务器发送数据,服务器也能向客户端发送数据。
当客户端断开连接的时候,申请断开的是客户端向服务器发送数据的通道,当客户端向服务器发送数据的通道关闭之后,客户端还不能退出,因为客户端还可能有数据要收取。
这个时候服务器可能还有数据还未发送完给客户端。服务器向客户端发送数据的通道还不能关闭。等待服务器发送数据完毕之后,才会发送FIN数据包,并且要等待客户端的回应,因为FIN数据包可能会失效,所以客户端还需要再次向服务器发送ACK确认应答包。当服务器收到客户端的ACK时,才会真正关闭。
这就需要四次挥手。
客户端为什么要等待2MSL
MSL指的是 Maxium Segement Lifetime,报文最大生存时间。当客户端收到FIN包后,会等待2MSL时间,如果在2MSL时间内,没有再次收到FIN包就会关闭客户端。
因为害怕服务器没有接收到客户端发来的ACK包,当服务器过了超时时间没有接收到ACK包的话,服务器会重新发送FIN包,客户端会重新发送ACK包,然后将等待时间重新初始化为2MSL。