问题背景
“为什么TCP要握手3次挥手要4次”是一道很常见的面试题。以前笔者一直不明白这个问题有什么好问的,而且看了大部分博客的答案好像就是说连接过程的(对答案不是很满意啊);现在自己作答希望能把逻辑讲圆,欢迎大家留言批评指正:)
阅读本文前建议快速scan一下《三个角度看TCP连接建立与结束》作为基础知识的预热。
本文先说握手。
最少交换3次
这句话进一步解释一下(important!)
- 不能少于3次,因为少于3次信息交完不完,所以不可能是0,1,2;
- 3次可以传够信息
- 多余3次当然可以把信息交换清楚,而且TCP握手过程却是也可以出现这种情况,但3次是最少也是最常见的交换模式;
交换的是什么
Richard Stevens原话中有一个关键词是exchange(交换),但exchange的是什么呢?
TCP设计了sequence number,ack,MSS,advertised window等机制, 这些机制需要在数据传输前先约定好初始值,这些初始值的交换至少需要两个TCP segment;同时TCP中采用了ack机制来保证传达,所以还需要最后一个单独的ack和中间和信息一起发的ack确认两边初始信息都正确传达了。
>3次?
小于3次的问题很清晰了,不多赘述了; 多于3次的问题可以再多说两句,认知要点有三个,总结一句大白话是:一般1没必要2浪费,但有一些情况会出现。
双向连接分开一个个建立变成4次握手并没有什么必要。TCP正常的使用场景是C-S架构模式下的双边通信:只有一边发送的场景并不是常见场景,所以并没有需求先建一个单向的half-connection再看情况建另一个half-connection;此外一般是C端主动发起连接,也不常见S也一起发起主动连接。这个是为什么连接建立时不用断开时的4次。(这里相关的两个话题是4次挥手为什么不是3次,还有就是另一个协议叫做SCTP的握手为什么是4次,后面我们分析)
啰嗦的语言可能也能转达信息,但是信息输出密度就低很多了。沟通是有成本的,时间、带宽和kernel的处理能力。
多次握手确实存在
什么时候多次握手会出现,其实看过TCP状态机的大家都应该见识过,可能只是没有从这个角度来思考吧。对比一下上面正常三次握手的图,和链接建立过程的状态机会发现状态机中的信息量是远远超过3次握手的。其中一组多出的信息是passive open,active open和simultaneous open。
在三次握手的时候一端(通常是client端)主动发起连接,称为active open(主动连接);另一端(通常是服务端)被动接收sync,称为passive open(被动连接)。在一种比较少见的使用场景里,两端互相知道对方的ip+port,在接收对方的sync前分别向对方发sync包,这中连接方式称为simultaneous open (simultaneous是同时的意思)。
具体4次握手可以参考上图,这时候两方连接是对称的,都经历了sync_send和sync_received状态。simultaneous open存在但是十分少见:因为这种连接方式需要两端都知道对方的ip+port并主动发sync包;而tcp主要用于C-S的架构,在CS架构下,C端一般没有公网ip没法直接从server端主动建立路由规则。
握手次数的本质
讲到这里TCP为什么3次握手其实已经讲完了,再精炼一下。握手次数核心在于1)连接建立需要双方交互的信息,注意这里的信息不是量的问题,大白话讲就是要交换几趟/个来回信息才能满足这个通信协议的机制启动),和2)加一个ack,往往最后一个ack没法合并。
下面讲一个4次握手的协议来强化一下这个核心道理的提炼:))
正常就4次握手的协议
在传输层除了UDP和TCP之外第三名可能是SCTP协议,这种协议正常的连接建立就是4次握手。这里需要多一次的原因是除了sync的双向确认,还需要cookie的双向确认;sync的双向确认主动发起的是client端,cookie是server端下发;sync 3次,cookie 3次,把6次中中间能合并在“一趟”里的信息合并成为4次。
SCTP前两次交换了核心信息:Ta,Tz;J,K(相当于tcp中的ISN);Cookie。并ack了客户端的int。四次的争议在于最后两次是不是可以缩减成1次。设计成3次其实可以work,相当于带cookie防止DDoS的TCP连接;但是设计成4次可以兼顾安全与效率:
- 新增了cookie的校验过程,server回复ack才认为cookie被服务端认可并以cookie内的信息创建了连接(这个是cookie模式与前文TCP安全模式中sync backlog模式不同的点,cookie模式可以防止DDoS攻击);
- 同时新增了ack使得cookie校验过程中可以进行数据夹带,这样ack同时可以确认数据,在增加了一个segment之后同时也提高了效率。