三次握手:
客户端→服务端,客户端进入sent状态;
服务端→客户端,服务端进入received状态;
客户端→服务端,客户端进入established状态
为什么要进行三次握手而不是两次(不要最后一次):
因为如果服务端收到来自客户端的前面一次走失连接请求,但是这个时候客户端已经不想维护这次请求了,第三次握手就可以确保客户端是否维护这个请求(第三次握手 === 客户端对服务端说我们俩维护这个连接)。
四次挥手:
客户端→服务端,客户端表示再也不发送数据了,客户端进入fin_wait_1状态;
服务端→客户端,服务端表示知道客户端再也不发送数据了,但是服务端可能还有数据要发送,比如说有的数据没发完呢。服务端进入close_wait状态,客户端进入fin_wait_2状态;
服务端→客户端,当服务端发完了所有的,发一个fin给客户端表示服务端也不用发东西了。此时服务端进入last_ack状态。
客户端→服务端,客户端发送ack表示知道服务端不发数据了,这个时候客户端进入time_wait状态,并等待一段时间(一般是两倍的最大生存时间),等完了客户端就进入closed状态。服务端收到客户端发过来的ack就进入closed状态。
为什么不能只有两次挥手(客户端发送fin,服务端收到后将所有数据发完再发送ack并且关闭服务端,客户端收到ack后关闭):
有可能在将所有数据发完这个过程中,客户端以为服务端没收到,所以重传了一个释放请求,这样服务端收到后就会关掉两个连接。
有可能服务端发的那个ack比它前面发的数据还早到达客户端,客户端收到后直接关掉了,这样就没有收到完整数据。
为什么客户端要进入时间等待状态:
如果没有时间等待状态而是客户端发完ack确认报文后就直接关闭,那就有可能出现ack确认报文段发在路上丢了,此时服务端就会超时重传释放报文段,但此时客户端已经关闭了,所以吃了闭门羹就会一直重传。
题外话,为什么tcp的释放有fin就要有ack?
因为tcp是全双工通信,为了保持连接状态一致性所以一定要有一个fin就有一个ack,不然就谁知道有没有到达。
以上图片来自bilibili up主——湖科大教书匠,侵权请联系我删除。