理解TCP和UDP
一、TCP端口
二、TCP报文结构
三、TCP连接的建立和释放
TCP
的整个交互过程可总结为:先建立连接、然后传输数据、最后释放连接。
其实网络上的传输是没有连接的
,TCP所谓的连接
,只不过是通信双方维护一个连接状态
,看上去像是有连接
三次握手,连接建立过程
TCP
连接的建立采用客户-服务器方式,主动发起连接建立的一方叫客户端client
,被动等待建立连接的一方叫服务端Server
。
- 最初,两端都处于
CLOSED
状态,然后服务器打开了TCP
服务,进入LISTEN
状态,监听特定端口,等待客户端的请求 - 第一次握手:客户端主动打开连接,发送
TCP
报文,进行握手,然后进入SYN_SEND
状态,等待服务器发回确认报文。首部同步位SYN置为1,同时初始化一个序列号Sequence Number=X,TCP
规定,SYN
报文段不能携带数据,但是会消耗一个序号 - 第二次握手:服务器收到了
SYN
报文,如果同意建立连接,则向客户端发送一个确认报文,然后服务器进入SYN_RCVD
状态,首部SYN和ACK都置为1,确认号Acknowledge Number=X+1,同时为自己初始化一个需要Sequence Number=Y 次报文同意不带数据 - 第三次握手:客户端收到服务器发送的确认报文,还要向服务器给出确认,然后进入
ESTABLISHED
状态,这时首部的SYN不再置为1,而ACK置为1,确认好Acknowledge Number=Y+1,序号Sequence Number=X+1,这次会携带真正的需要传输的数据,当服务器收到该数据报文时,就会同样进入ESTABLISHED
状态,此时TCP
建立连接
对于建立连接的三次握手,主要目的是初始化Sequence Number,并且通信的双方都需要告知对方自己的初始化序号,此过程也叫
SYN
阶段.
这个序号是作为接下来数据通信的序号,用来保证应用层接受到的数据不会因为网络上的传输问题二乱序
,TCP
需要用序号进行数据拼接
四次挥手,释放链接
TCP
的连接是全双工(可以同时发送和接受)的连接,因此在关闭连接时,必须关闭传送和接收两个方向的连接
客户端给服务器发送一个携带FIN
的TCP
结束报文,然后服务器返回给客户端一个确认报文,同时发送一个结束报文,当客户端恢复一个确认报文后,连接结束
结束之前都处于ESTABLISHED
状态,模拟客户端先主动断开连接
- 第一次挥手:客户端向服务器端发送结束报文,然后进入
FIN_WAIT_1
状态,此报文FIN
置为1,Sequence Number=M - 第二次挥手:服务端接收到客户端的结束报文,发送确认报文,进入
CLOSE_WAIT
状态,此报文段ACK置为1,Sequence Number=M+1,客户端收到该报文,进入`FIN_WAIT_2 状态。 - 第三次挥手:服务端向客户端发送结束报文,然后进入
LAST_ACK
状态,此报文FIN
置为1,Sequence Number=N - 第四次挥手:客户端收到服务端的结束报文,然后发送确认报文,进入
TIME_WAIT
状态,经过2MSL时间之后,自动进入CLOSED
状态,报文ACK置为1,Sequence Number=N+1,服务器收到报文后,进入CLOSED
状态
Client
CLOSED -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED
Server
CLOSED -> LISTEN -> SYN_RECEIVED -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
MSL
Maximum Segment Lifetime
(数据包的最大生命周期),是一个数据包能在互联网上生存的最长时间,若超过这个时间则该数据包将会消失在网络中。
操作系统通常会将2MSL
设为4分钟,最低不少于30秒,因而``TIME_WAIT状态一般维持在30秒至4分钟。这个是TCP/IP设计者设计的,也就是无法解决的。
TIME_WAIT
TIME_WAIT
状态的存在主要有两个原因:
可靠地实现TCP全双工连接的终止
关闭TCP时,最后的ACK
包是由主动关闭方发出的,如果ACK
包丢失,被动关闭方将重发FIN
包,因此主动方必须维护状态信息,以接收它重发这个ACK
包。如果不维持这个状态信息,那么主动方将回到CLOSED
状态,而被动方重发的FIN
包响应RST
包,产生一个错误,为避免四次握手协议中包丢失的情况,主动关闭方必须维持TIME_WAIT
状态。
确保迷路数据包重新出现而影响新连接
TCP
数据包可能由于路由器异常而迷路,在迷路期间,数据包发送方可能因超时而重发这个包,迷路的数据包在路由器恢复后也会被送到目的地,这个迷路的数据包就称为Lost Duplicate
。
在关闭一个TCP
连接后,如果马上使用相同的IP地址和端口建立新的TCP连接,那可能出现迷路重复数据包在前一个连接关闭后再次出现,影响新建立的连接。为了避免这一情况,TCP
协议不允许使用处于TIME_WAIT状态的连接的IP和端口启动一个新连接,只有经过2MSL
的时间,确保上一次连接中所有的迷路重复数据包都已消失在网络中,才能安全地建立新连接。
对于Client而言,每个连接都需要占用一个端口,而系统允许的可用端口数不足65000个,大量建立连接和主动断开,会耗尽端口
对Server而言(特别是处理高并发短连接的Server),Server对每个端口上的连接数受到文件描述符的最大打开数的限制。所以,如果Server主动关闭连接,也会出现端口耗尽的情况
CLOSING
不管如何
CLOSING
状态的TCP
连接,即便没有收到自己发送FIN
之后的ACK
,也不会永久保持下去,保持多久取决于自己发送FIN
时刻的RTT
,然后RTT
计算出的RTO
按照最大的退避次数来退避,直到最终执行了固定次数的退避后,算出来的那个比较大的超时时间到期,然后TCP socket
就销毁了。
- RTO(Retransmission TimeOut)即重传超时时间
- RTT(Round Trip Time)即往返时间,由三部分组成:链路的传播时间(propagation delay)、末端系统的处理时间、路由器缓存中的排队和处理时间(queuing delay)。
其中,前两个部分的值对于一个TCP连接相对固定,路由器缓存中的排队和处理时间会随着整个网络拥塞程度的变化而变化。所以RTT的变化在一定程度上反应了网络的拥塞程度
四、TCP状态流转
image.png-
CLOSED:
初始状态 -
LISTEN:
socket处于监听状态,可以接受连接 -
SYN_SENT:
客户端发送SYN报文,然后进入SYN_SENT状态,等待服务端确认 -
SYN_RCVD:
服务端接受到SYN报文 -
ESTABLISHED:
连接已建立 -
FIN_WAIT_1:
一方请求终止,等待对方FIN报文 -
FIN_WAIT_2:
对方回应了ACK报文之后进入此状态 -
TIME_WAIT:
接收到对方FIN报文,并自身响应ACK后,进入此状态 -
CLOSING:
罕见状态,在接收到对端ACK之前先接收到了FIN包,直接从FIN_WAIT_1进入CLOSING状态 -
LAST_ACK:
被动关闭的一方发送FIN后,等待ACK所处的状态 -
CLOSED:
等待超时进入CLOSED