《张三求职日记》基础篇--(5)TCP三次握手与四次挥手

154 阅读10分钟
写在前面:既然前一篇就问到了网络协议相关的知识,那么对于我们而言,必然绕不开的就是TCP/IP协议族,但是这个协议族太大了,三本书都讲不完,而且工作了多年的面试官也不一定能完全掌握,而经验并不丰富的我们也不需要死磕在它上面,但是TCP协议的基本概念以及三次握手和四次挥手还是一定要好好掌握的。有关于张三的背景介绍参考: 张三背景介绍

张三又开始了新的一轮面试。

面试官:先来个自我介绍吧。

张三:!@#¥%……&*。

前面的一阵交谈此处省略

面试官:TCP协议你说说看吧。

张三心想,我刚好面试前把TCP相关的很多东西都看了,回答这个应该问题不大吧。

张三:TCP啊,它是位于传输层的,面向连接的,可靠的,基于字节流的协议。

面试官:那你说到了面像连接,那什么是连接呢?

张三:TCP传输数据前需要先建立连接,而UDP不需要建立连接,即刻传输数据。

面试官:没回答到点子上啊。

张三有点慌了,这么标准还没回答到点子上?你到底是想问什么呀,张三陷入了沉思……

面试官:三次握手有了解吗?

张三心里叹了口气,原来是想问三次握手啊,不能直接说吗,不过想想也怪自己,这都想不到一块去(当然其实如果想讲连接的定义的话又是另一回事了)。

张三:三次握手当然是了解的,它是TCP协议建立的过程,三次握手按我的理解呢就是,我向你发送了一串信息说我想和你建立连接,你收到后告诉我你收到了我想建立连接的请求,并且同时告诉我你也想和我建立连接,我在收到你的请求后再向你发送一串信息表示我收到了你的请求。

面试官:那如果是两次或者是四次行吗?

张三:如果是两次的话,那就是我给你发了建立连接的请求,而你回了我,这只能说明你我都知道我能联系上你,但是你给我发建立连接的请求时我不回你的话,你并不知道你给我发的信息我是不是真的收到了,这样就连接不可靠了。而如果是四次的话,我都感觉是没有必要的,因为三次连接覆盖了完整的场景,应该已经够了,三次如果不能保证的话四次也没有办法,多出来的连接浪费资源。

张三心想,我可是看了博客带着自己的理解回答问题的,这样答应该很不错吧。

面试官:那四次挥手了解吗?

张三:四次挥手按我都理解就是,我给你发信息说我想断开连接,而你回了句好多,然后你给我发你想断开连接,我发了句好的,然后我们就断开连接了。

于是面试官又换了个问题继续问,但是张三能感觉到面试官的语气并不是很满意,也不知道自己究竟哪做的不好。后面的问题省略。

面试官:这次的面试就先到这里,后面会有我们的HR联系你。

张三:好的……

---------------------------------------------------------------------------------

那么张三到底哪做的不好呢?其实张三回答的都没有错,很多人能回答到张三这个层次已经不错了。但是如果我们想追求更高的评价的话,我们需要有更加专业的回答。相信大家在学习三次握手的时候肯定学过了什么SYN,ACK这样的名词,但是过了一段时间后自己怎么也记不住,导致回答的时候只能模棱两可的回答三次握手的过程。其实说的专业和不专业能有啥区别呢?对于普通开发来讲,反正都用不到,了解的多一点少一点真的区别不大。但是如果我们能表现的更好一点,就有更多的底气了。而张三显然只是看看了知识点,并没有深入研究过,而只要花点时间在它上面,大家都能够比较专业的回答这个问题。

既然TCP建立连接是三次握手,那么我们先探究是不是,再探究是什么,再探究为什么。

那么TCP建立连接到底是不是三次握手呢?很简单,首先我们先在linux上敲如下的命令来把网络中传输的数据包的包截获下来分析:



肯定有很多同学敲tcpdump命令报错的,所以我也很贴心的为大家准备了tcpdump的安装命令:yum install tcpdump

然后我们另起一个连接(该不会有人敲命令是直接在linux上敲的吧)通过curl命令访问百度:



我们看到百度已经给我们返回HTML的页面了(有linux不能上网的同学自行解决),所以我们回过头来看之前监听的信息,发现给我们打印了11行信息,前三行是和建立连接有关的,中间四行是和传输数据有关的,后四行是和断开连接有关的,所以我们先来看前三行:


抓到的字段还不少呢,以前学的东西都忘的差不多了,那我们先来找找规律吧。诶,发现了一点,第一行的seq+1就等于第二行的ack,而第一行的win和第三行的一样,嗯好像找不到别的了。

那么既然找到了规律,那就查查看seq和ack是什么吧:

seq是sequence number,中文翻译叫做序列号,那它是干什么的呢?根据查询的资料解释:TCP 是面向字节流的,通过 TCP 传送的字节流中的每个字节都按顺序编号,而报头中的序号字段值则指的是本报文段数据的第一个字节的序号。

ack是acknowledge number,中文翻译是应答号,解释为期望收到对方下个报文段的第一个数据字节的序号。

那我们再来看看这张经典的解释三次握手的图:



有些人直接看懵了,怎么又是大的ACK又是小的ack,SYN和seq的关系到底是啥,这么多+1又是为什么?

所以我开始解释了,虽然不同人画的都有区别,但是也大同小异,都是这样的三次握手:
  1. 客户端向服务器发送一串TCP报文,那么我们先介绍一下一串TCP报文中主要有哪些东西(参考大佬博客的图):

    那我们再看三次握手的图,是不是就很清晰了,第一次握手发送的seq就是32位序列号,在我们截获下来的数据包中就是3746534935这串数字,而SYN就是报文中的SYN位置对应的数据。所以第一次握手发送的是SYN=1(这是默认的),同时也把序列号(seq)的信息也发过去了。
  2. 那么第二次握手呢,我给你发送了报文,我不知道你收没收到啊, 你要是收到了一定要回我啊,回我我要能知道是因为我发送的报文而回的啊,所以服务端该怎么办呢?既然要能让你知道是因为你发送的报文而回的,那我就回个你给我的+1吧,这样你就知道因为你找我所以我回你了。所以这边回的应答号(ack)为你发的序列号(seq+1)。那么我还要告诉你这是回的请求,并且我同意了,所以在ACK这个位置放个1来告诉你。然后呢,前面是你想和我建立连接,我回了个ack和ACK来确定了你发信息到我这里来是通畅的。而我也想与你建立连接,所以我也要发seq和SYN。所以综上,在这一次握手里发送的是回应的**ACK=1**和**ack=x(第一次握手发过来的seq)+1**以及**SYN=1**和**seq=y**。这样记应该大家都能记住吧。
  3. 所以第三次握手理论上应该只是个应答,应答个**ACK=1**以及**ack=y+1**就够了,然而图上多画了个seq,虽然不能确定是不是这样吧,但是如果看ack的解释还是合理的。

然后我们回到上面看我们截获的报文,老脸一黑,这第一次第二次都能对应的上,为什么第三次对应不上呢?我也不清楚,但是我们把三次握手的标准解释记住了,有关于截获的报文为什么对不上的问题,只能以后再仔细研究了。

我们以后再回答三次握手的时候应该就能专业许多了吧:第一次握手是客户端想与服务端建立连接,所以发送了seq=x以及SYN=1。第二次服务端要应答客户端的请求并且服务端也想与客户端建立连接,所以发送的报文是ACK=1、ack=x、SYN=1以及swq=y。第三次是客户端回应服务端的请求,返回的是ACK=1以及ack=y+1(看面试官脸色要不要讲seq)。

那么我们三次握手的流程搞得很清楚了,那么能不能两次握手或者四次握手呢?

先说两次握手吧,两次握手的情况就是少了第三次的回应的报文的发送。首先肯定就是没法确定服务端是否与客户端的通信是不是正常这一点大家都能清楚。那么还可能有什么情况发生呢?假设是两次连接的情况下,客户端给服务端发送了请求报文,但是客户端吃吃不回,客户端以为服务端没有收到,于是又发生了一次,但是这新的一次的连接还没走完,这时候服务端返回了第一次客户端的确认请求。那这时候怎么办呢,如果客户端认可这个连接的话,那就多次连接浪费资源了,如果不认可的话服务端又没法知道,就会出现问题了。所以两次握手肯定不可以。

那么四次握手呢?四次握手发什么呀,根据我们上面的分析第三次只需要回应就行了,真的不需要第四次握手。

最后我们在给一下四次挥手截获的数据包,大家按这个思路自己分析记忆:



有关于TCP能讲的东西还有很多像什么流量控制,拥塞控制,可靠性传输等更深以层次的知识需要感兴趣的你们自己去摸索了。

张三在这次的面试中收获颇丰,我们下周见。