TCP的三次握手已经说烂了,TCP为何要三次握手?为何不两次握手也有很多说法。对于这些类似的问题,最好的办法是看RFC

常规思路,由面到点

  • 两军问题

在不可靠通信下,两军想要达到状态一致是无解的。因为在不可靠信道下,一边状态的确认需要另一边的回复(ACK),而另一边回复时再次面临不可靠信道问题,这样就回到了问题的最初,无限递归

既然“两军问题”无解,TCP也面临此问题,为何TCP还能可靠传输数据呢?

两军A,B为达成一致状态,A需要知道B是否收到信息(A-->B),B需要知道A是否知道B已经收到信息(B回复ACK)(B-->A)

但对于TCP,A只需要知道B有没有收到信息,并不关心B是否知道A已经知道B已经收到信息(这里语言表达不太友好...),只要网络不是100%不可靠,这个是可以实现的(例如通过超时重传机制辅助)。即:TCP并不需要两边状态一致

感觉有人要打我脸了,用过钉钉的人会说,A发送给B一条消息,B看到后会显示“已读”,你看,在不可靠的网络上这不状态一致了么?额。。。

这里有两个惯性思维

1.一般用户甚至程序员会理所当然的认为网络,通信软件是可靠的(这个只能说国内的公网还不错),认为B收到A的消息并且看了以后,A那端一定会显示“已读”

2.上帝视角。A和B是同时在你的脑袋里虚拟的角色,B通过你这个上帝得知了A的情况而不是通过“不可靠信道”

这是环境使然,打破这个只能靠逻辑,或者换一个环境

我们换一个环境:

在战区,电磁干扰很严重,A给B发送了一条消息,虽然A端显示已读,但这时候B就懵逼了:A有没有收到?(还深信不疑只要B看了A就一定收到且显示为“已读”么?)

当然此时很多人还是会质疑我:平时约朋友,A发消息:晚上5.见,B回消息:好,5.见。这事就定了啊,实际也就是这样约到的啊?!。。。

这里的问题在于:

1.国内的公网大多数情况下是可靠的,尤其对于IM这种消息量不大的应用体现更为明显,所以给人造成刻板印象,A发出去的B一定能收到,A也一定能收到B给的ACK

2.事情本身的风险很小(能容忍的不确定性很大)

我们用“笨方法”分析

A ----> B  (A向B发送消息:晚上5.见)

B ----> A  (B收到消息回复ACK

A收到ACK并显示“已读”,此时A,B各自的状态为:

A:知道B收到了消息

B:不知道A是否收到ACK,即:不知道A是否知道B收到消息“晚上5.见”

设定一个场景,A,B必须同时在5.约定的地点出现,否则单方出现的会被出卖,即:任何一方都不能冒险,必须100%确定

由于B 不知道 A 是否知道B已经收到消息,所以没法100%确定,所以B不会赴约

A也知道B会这么想,所以A也不会赴约

继续:

B ---->  A   (B向A发送消息:好,5.见)

A ---->  B   (A向B发送ACK)

B收到ACK并显示“已读”,此时A,B各自的状态为:

A:不知道B是否收到ACK,即:不知道B是否知道A收到消息“好,5.见”

B:知道A收到了消息

综合上面的情况:

A:确定:B收到了消息“晚上5.见”,确定:B不确定A知道B收到消息“晚上5.见”,不确定:B知道A收到消息“好,5.见”,

B:确定:A收到了消息“好,5.见”,确定:A不确定B知道A收到消息“好,5.见”,不确定:A知道B收到消息“晚上5.见”

此场景“不确定”会被认为“没有,不会,没发生”

A的视角:B收到了消息“晚上5.见”,B会认为我这边显示发送消息“晚上5.见”失败,B认为:我会认为B显示发送消息“好,5.见”失败

B的视角:A收到了消息“好,5.见”,A会认为我这边显示发送消息“好,5.见”失败,A认为:我会认为A显示发送消息“晚上5.见”失败

这里最容易脑卡的地方在:

1.B确实收到了A发的消息“晚上5.见”,A也知道B收到了这个消息,但从B的角度,B无法确定A收到了ACK,所以只能认为A没有收到ACK,从而认为A显示发送消息“晚上5.见”失败

2.B是否赴约取决于B认为A是否会赴约,当前的不确定性和风险让B认为A显示发送失败,从而认定A不会赴约

在不可靠背景下,发送ACK的一方都会认为对方没有收到ACK,从而认为对方会认为对方自己之前发送的消息失败,无法达到一致

我们再看,A会赴约么?A赴约与否取决于从A的视角看B会不会去赴约

A的视角认为:B会认为我这边显示发送消息“晚上5.见”失败,B认为:我会认为B显示发送消息“好,5.见”失败

简单的说就是:B认为我没发消息“晚上5.见”,B也会认为:我认为B没发消息“好,5.见

A,B就是两个杠精,相互否认。。。谁敢赴约?。。。

  • ISN

如果是两次握手,B收到A的SYN包后状态即为:ESTABLISHED,此时B再给A发送一个SYN+ACK包,由于此时B已经为ESTABLISHED,所以可以向A发送数据,如果数据包先于SYN+ACK包到达A,A就尴尬了,A没有收到B的ISN,没法判断这些数据包是否能用(< ISN 该直接丢弃),一个优雅牛逼的协议是没法容忍这些的

如果是三次握手,B收到A的SYN包后状态即为:SYN_RECV,是没法发送包的

但有一点是相同的,无论是SYN_RECV或者ESTABLISHED,都是一种等待状态,都需要发送数据包确认对方是否还在(SYN_RECV会出现SYN flood)

你可以设计两次握手,但相应的状态机也需要重新设计,TCP目前的状态机仅仅是多种设计方案中的一种,真要谈两次握手需要重新设计协议,在协议内部(尤其是状态机已经确定)谈为何不两次握手意义不大,毕竟这仅仅是整个协议的一部分,此时需要的是从整个协议的角度思考

  • 四次握手

三次握手在机制上本质是四次握手的简化

1.A ----> B (SYN,ISN)

2.B ----> A  (ACK)

3.B ----> A  (SYN,ISN)

4.A ----> B  (ACK)

2和3合并后成了“三次握手”,四次握手建立连接和四次握手关闭连接是对应的,体现了全双工

更多次握手能从整体上衡量出在一个时间段内网络是否可靠,握手次数要求越多,对那段时间的可靠性要求也高,但从工程上没有太大必要

1.TCP是兼顾效率和可靠性的协议

2.网络的稳定性存在随机性,也许开始很好,接下来就拥塞了,此前的握手再流畅也是然并暖

握手并不是为了处理可靠性问题

这里也许会刷新你对习以为常的网络是可靠的惯性思维,如今人们把状态一致的重任交给了依靠公网的IM,刻板印象中也没出过错,但大概率不出错不表示100%不出错,从理论的完备性看,IM无法担当状态一致的重任

但我们何尝又不是活在一个不确定的世界中,云服务SLA最多给你6个9,银行金融系统都不是100%可靠,电力系统,飞机,卫星,火箭,高铁都是这样,但我们依旧活的似乎“很确定”

习惯了大概率的确定性,面对真实的不确定时会手足无措,难以接受

习惯了不确定性,面对大概率的确定性时,感叹的可能是一种难以描述的舒适和震感

TCP两次握手的更多相关文章

  1. TCP 两次握手为什么无法阻止历史连接?

    摘要:在两次握手的情况下,「被动发起方」没有中间状态给「主动发起方」来阻止历史连接,导致「被动发起方」可能建立一个历史连接,造成资源浪费. 本文分享自华为云社区<TCP 两次握手为什么无法阻止历 ...

  2. 活久见!TCP两次挥手,你见过吗?那四次握手呢?

    活久见!TCP两次挥手,你见过吗?那四次握手呢? 文章持续更新,可以微信搜一搜「小白debug」第一时间阅读,回复[教程]获golang免费视频教程.本文已经收录在GitHub https://git ...

  3. 两将军问题和TCP三次握手

    两将军问题,又被称为两将军悖论.两军问题, 是一个经典的计算机思想实验. 首先, 为避免混淆,我们需要认识到两将军问题虽然与拜占庭将军问题相关,但两者不是一个东西.拜占庭将军问题是一个更通用的两将军问 ...

  4. TCP为什么不是两次握手而是三次?

    为什么不采用两次握手?如果是两次握手的情景:客户端在发送一个连接建立请求之后进入等待状态,等到服务端确认之后就进入established状态.服务端在发送一个确认连接建立请求报文之后(不管客户端是否有 ...

  5. TCP三次握手是什么?为什么要进行三次握手?两次,四次握手可以吗?

    1.第一次握手,发送SYN报文,传达信息:“你好,我想建立连接”: 第二次握手,回传SYN+ACK报文,传达信息:“好的,可以建立链接”:    第三次握手,回传ACK报文,传到信息:“好的,我知道了 ...

  6. TCP三次握手/四次挥手详解

    一. TCP/IP协议族 TCP/IP是一个协议族,通常分不同层次进行开发,每个层次负责不同的通信功能.包含以下四个层次: 1. 链路层,也称作数据链路层或者网络接口层,通常包括操作系统中的设备驱动程 ...

  7. TCP ,UDP概念和TCP三次握手连接 的知识点总结

    OSI 计算机网络7层模型 TCP/IP四层网络模型 传输层提供应用间的逻辑通信(端到端),网络层提供的是主机到主机的通信,传输层提供的是可靠服务. TCP 中常说的握手指的是:连接的定义和连接的建立 ...

  8. TCP三次握手和四次挥手状态变迁解析

    TCP是TCP/IP的传输层控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 首先需要了解几个名词:tcp标志位,有6种分别为:SYN(synchronous建立联机) .ACK(ackn ...

  9. Wireshark基本介绍和学习TCP三次握手

    wireshark介绍 wireshark的官方下载网站: http://www.wireshark.org/ wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示 ...

随机推荐

  1. C#C/S框架演示 (MES系统)

    之前做过一个MES系统,发一些里面的截图.如果有朋友也用这个框架.或者有兴趣可以一起学习学习.使用开发工具VS2013,数据库SqlServer2008和Oracle11C.插件dev15.2,开发模 ...

  2. 分布式 基本理论 CAP

    谈及分布式,必然谈到 CAP, CAP 已经是被说烂了的一个 话题, 绕不开, 逃不掉.  而且, 理解起来 会有些吃力. 分布式的CAP理论告诉我们 “任何一个分布式系统都无法同时满足 一致性(Co ...

  3. 《2018面向对象程序设计(Java)课程学习进度条》

    周次 (阅读/编写)代码行数 发布博客量/博客评论数量 课堂/课余学习时间(小时) 最满意的编程任务 第一周 50/40 1/0 6/4 九九乘法表 第二周 100/80 1/0 6/8 实验5,6, ...

  4. SpringBoot学习笔记1

    1.什么是SpringBoot 用一些固定的方式来构建生产级别的spring应用.spring boot推崇约定大于配置的方式便于你能够快速的启动并运行程序. 2.为什么要学spring boot j ...

  5. mongodb插入数据获取本次插入的mongodb id

    最近接了一个别人的项目做二次开发,使用php进行mongodb的数据操作时,需要插入数据后得到相应的mongodb 中的id,简单代码如下 $data = array('test' => 'aa ...

  6. Linux网络编程学习(七) ----- 有名管道(第四章)

    1.什么是有名管道?为什么有了管道还需要有名管道? 有名管道是解决管道不能提供非父子进程间通信的缺陷.管道在Linux系统内部是以文件节点(inode)的形式存在,但由于其对外的不可见性(“无名”性) ...

  7. 安装SQL server 2008 R2和QL server 2008,与SQL server 2008升级SQL server 2008 R2

    安装SQL server 2008 R2和由SQL server 2008升级SQL server 2008 R2 前提条件: 由SQL server2008 升级SQL server2008 R2 ...

  8. Day01 -Class类别 精选面试题

    30天修炼完成Ruby精选面试题! 我决定从学习Ruby on Rails开始着手!鼓励自己在短期间内专心学习与产出知识,为转职奠定良好的基础. A.首先:找寻方向,决定主题 我想很多人的状况都跟我一 ...

  9. 爬取github项目。

    import requests from bs4 import BeautifulSoup url = 'https://github.com/login' headers = { 'User-Age ...

  10. PostgreSQL 锁等待诊断详解

    摘要PostgreSQL和大多数传统RDBMS一样,都设计了大量的锁来保证并发操作的数据一致性. 同时PG在设计锁等待时,以队列方式存储等待锁. 参考 ProcSleep()@src/backend/ ...