概述
TCP是面向连接的协议。运输连接是用来传输报文的。运输连接的建立和释放在每一次通信中是必不可少的内容。因此运输连接分为三个阶段:建立连接、传输数据和释放链接。运输管理就是保证每一步都能正常运行。
在TCP 连接的建立过程主要解决三个问题:
- 要使每一方都能够知道对方的存在
- 要允许双方协商一些参数(如窗口最大值、是否使用窗口扩大选项和时间戳等)
- 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
一、TCP 连接的建立
TCP 的连接建立,我们常常称为三次握手。
A:您好,我是A。
B:您好,我是B
A:您好B。
连接过程
假设A 为客户端(上图左),B 为服务端(右)
- 一开始A、B 均为关闭状态。B先开启服务器,建立传输控制块TCB。准备接受连接请求,然后处于LISTEN 状态。等待用户连接请求并作出响应。
TCB:(Transmission Control Block,存储了每一个连接中的一些重要信息,如:TCP 连接表,指向发送和接受缓存的指针,指向重传队列的指针,当前发送和接受序号等等)
- A 也是先创建连接控制模块TCB 。然后A 向B 发送请求报文段,这时首部中的同部位SYN = 1,同时选择一个初始序号 seq = x。TCP 规定,SYN 报文段不能携带数据,但要消耗掉一个序号。然后客户端进入SYN-SEND (同步已发送)状态。
- B 接受到A 的连接请求后,如果同意连接需要给S 发送确认。确认报文段ACK 置为1,确认号ack = x+1,同时选择一个自己的初始序号seq = y。请注意这个报文段也不能传输数据,但也要消耗一个序号。这是B 进入SYN-RCVD (同步收到)状态。
- A 收到B 的确认后,需要发送一个确认给B。确认报文段ACK 置为1,确认号ack = y + 1,而自己的序号seq = x + 1,。TCP 规定,ACk 报文段可以添加数据。但如果没有添加数据则不消耗序号。这时,TCP 连接已经建立,A 进入ESTABLISHED (已经建立连接)状态。
- B 收到 A 的确认也进入ESTABLISHED (已经建立连接)状态。
为什么TCP 是三次握手?
假设A B 只用两次握手就建立连接。
当A 第一次发送给B 连接请求时,如果迟迟得不到回应,A会再次发送连接请求。那么现在网络中有两次请求,一般情况下第一次请求挂掉了,那么B 收到第二次请求,然后回应A,连接建立,没毛病。但是第一次请求可能只是滞后了,假设AB断开连接后,B 又收到了第一次请求,又会尝试建立连接,但是A 会觉得自己没有尝试建立连接,从而拒绝B。因为是两次握手,B 会以为自己已经建立连接了,等待A 发送数据,白白浪费资源。
三次握手就不会出现这个问题,B 在发送确认后,得不到A 的确认,就会知道这是个过时的请求,知道A 没有要求建立连接。
二、TCP 连接释放
好了,说完了连接,接下来说一说“拜拜”,好说好散。这常被称为四次挥手。A:B 啊,我不想玩了。
B:哦,你不想玩了啊,我知道了。
这个时候,还只是 A 不想玩了,也即 A 不会再发送数据,但是 B 能不能在 ACK 的时候,直接关闭呢?当然不可以了,,很有可能 A 是发完了最后的数据就准备不玩了,但是 B 还没做完自己的事情,还是可以发送数据的,所以称为半关闭的状态。
这个时候 A 等待 B 也主动关闭。
B:A 啊,好吧,我也不玩了,拜拜。
A:好的,拜拜。
释放链接的过程
首先AB 都处于ESTABLISHED 状态
- A 先发送连接释放报文段,并停止发送数据,主动关闭TCP 连接。A 把链接释放报文段首部的中止控制位FIN 置为1 ,其序号为seq = u(等于前一个传输数据的序号+1)。这是A 进入 FIN-WAIT-1(终止等待连接1)状态,等待B 的确认。TCP规定,FIN 报文段即使不携带数据,也会消耗一个序号。
- B 收到A 的连接释放报文段后发出确认。确认号ack = u + 1,而报文段自己的序号seq = v(等于前一个传输数据的序号+1)。然后B 进入CLOSED-WAIT(关闭等待)状态,这是A->B方向的连接就已经断开了,TCP 连接处于半关闭状态.
- A 收到B 的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B 发送释放报文段。
- 若B 发送完数据后,向A 发送TCP 释放报文段。FIN 置为1 ,先假设序号seq = w (B可能又发送了一些数据),B 还必须重复上次已经发送的确认号ack = u + 1。这是B 进入LAST-ACK(最后确认)状态,等待A 的确认。
- A 在收到连接释放报文段后发送确认。在确认报文段中把ACK 置为1 ,确认号ack = w + 1,而自己的序号seq = u + 1(TCP 规定,前面发送过的FIN 报文段要消耗一个序号)。然后进入到TIME-WAIT(时间等待)状态。
- 现在TCP 连接还没有断掉。必须经过时间等待计时器(TIME-WAIT time)设置的2MSL时间过后,A 才进入到CLOSED 状态。
MSL(Maximum Segment Lifetimr)最长报文生存时间,RFC793 建议为2 分钟。
- B 收到A 的ACK 后进入CLOSED 状态
为什么A 在TIME-WAIT 必须等待2MSL时间?
- 为了保证A 发送的最后一个ACK 报文段能够到达B。
- 防止已失效的连接请求报文段出现在本链接中。A 在发送完最后一个ACK 后,在经过2MSL 的等待时间可以保证本链接持续时间内发送的报文在网络中消失。这样就不会出现旧连接请求出现在新连接请求里面的情况
TCP 保活计时器
除了时间等待器外,TCP 还设有一个保活计时器(keepalive timer)。
当客户与服务器建立了连接,而客户出现故障无法响应客户端时,服务器就会发一个探测报文,75秒发一个,若连续发10 个客户端都没响应,则服务器端自动关闭连接。保活计时器默认为2 个小时,每收到一次请求刷新。
TCP 状态机
参考资料
- 极客时间:《趣谈网络协议》
- 《计算机网络》