关于TCP三次握手的理论知识,往上一搜一大片,本文就跳过理论,直接上手。Let’s go。
开启三个窗口,窗口1执行命令:
这个命令用来抓包,抓的是7899端口的包。-A和-X是为了显示详细的包内容,方便分析。如果不习惯用tcpdump直接分析,也可以使用wireshark,更加直观一些。
窗口2执行命令:
该命令监听7899端口,相当于启动了一个监听7899端口的server。当然你要是有兴趣的话,可以用代码写一个server。
窗口3执行命令:
这个命令是向127.0.0.1:7899建立连接,相当于client执行connect函数。
这个命令一执行,就会连接到7899端口上 ,在第一个窗口上立即就会抓到连续的三个包,如下图所示:
如上步骤,演示了TCP建立连接的过程,tcpdump抓到的三个包,正好就是三次握手。
很多资料讲解三次握手时,都会有一幅类似于这样的图:
我们对应抓到的三个包来看。
第一个包:
第二个包:
第三个包:
这个步骤,和上图大致是能一一对应上的。
除了这些简而易见的信息,还有一些 可能一时半会儿看不懂的东西,比如:
要了解这些东西,需要先了解TCP协议栈。
相关视频推荐
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
首先,我们应该知道,一个完整的以太网帧,包含了ethdr + iphdr + tcpdhr + data + etend
其中,以太网头占14字节,IP头占20字节,TCP头占20字节,以太网尾占4字节,应用数据大小不定,但不会超过一个MTU。
因为我们只研究三次握手,所以关于以太网帧,了解这些就够了。
我们再来看看具体的TCP协议栈:
TCP协议栈包含:
16位源端口号,占2字节
16位目的端口号,占2字节
32位序号(seq),占4字节
32位确认序号(ack),占4字节
4位首部长度,占0.5字节
6位保留位,占0.75字节
6位标志位,占0.75字节, 以上:4位首部长度+6位保留长度+6位标志位,合计16位,计2字节
标志位包括:
URG
16位窗口大小(window size),占2字节
16位校验和(checksum),占2字节
16位紧急指针,占2字节
有了以上这些知识,我们再来解析上面的协议栈。
十六进制报文中,前20个字节是IP协议头,后20个字节虽然也属于TCP协议 ,但是是可选项option,并非标准的TCP协议一定有的内容,所以我们真正关心的内容 , 是下面高亮的部分:
即:
接下来,我们逐个字节解析:
16位源端口, 即 bd40, 转换成10进制为48448
16位目的端口,即1edb,转换成10进制为7899
32位序号:b5dc f355, 即3051156309
32位确认号:0000 0000,即0
后面三个域由于不是 完整的字节,放在一块解析:
标志位要解释一下 :
标志位哪一位设置为1,就代表当前属于什么包
由上面对应关系,可知当前是一个SYN包。
16位窗口大小:ffd7, 即65495
16位校验和,即:fe30
16位紧急指针,即0000
由以上内容,我们提取一些关键信息:
第一次握手:
由上面的知识,我们知道TCP报文主要是下面这段:
通过同样的方法,可以解析出:
第二次握手:
TCP协议部分:
可以解析出 :
第三次握手:
以上内容,如果用比较直观的方式总结一下 ,大约如下图:
又回到老生常谈的话题:为什么需要三次握手?少一次行不行?只握手一次成不成?
在聊这个话题之前,我们引入一下著名科幻小说《三体》中叶文杰教主和三体文明建立联系的过程。
首先,叶教主向三体文明发送了一条消息,紧接着,三体人回复了一条消息,内容是“不要回答,不要回答,不要回答!”然后叶教主回复了这条消息 ,导致地球成功被三体人定位。
不得不说,大刘是懂TCP协议的。至少他懂三次握手的重要性。
第一次发消息,你说三体人收到没有?肯定是收到了的。但这个连接可靠不?明显不可靠。对于三体人来说,他怎么知道这个消息是谁发的?发消息的文明是否还活着?对于地球来说,更是如此,他怎么知道 这条消息对方肯定收到了?又没有人收?
第二次发消息,三体人差不多要把ACK标志写在脸上了,就是明明白白告诉你,我这是一个ACK消息,你只要不应答这个ACK,我们这个连接就建立不成,三体小说就全剧终。这就相当于三体人告诉叶教主:我活着,并且能收到你的消息,但是我还不知道你是谁,你能不能收到我这条消息。
所以第三条消息,狡猾的大刘当然不会让三体就此game over,就是老叶告诉三体人,我也能收到你的消息,从此以后,咱们是“同志”了。
类比三次握手,和这个步骤非常相似,缺少其中任意一环,这个连接都是不可靠的,因为你不知道对方能不能收到我的消息。所以三次握手,并不是表示连接“可达”的,而是表示连接“可靠”的。这之间是有区别的,可达很简单,UDP也能可达,一次握手也是可达的,但是并不可靠。因为无法知道这条消息对方能不能正确接收到。只有这样反复确认后,才能表示这个连接是可靠的连接。
有杠精肯定表示不服,说理虽然是这么个理,但是会不会有巧合啊。比如某个服务既是客户端又是服务端,我在给你发第一次握手的时候,你也恰好在给我发第一次握手,让我误以为你给我的消息是第二次握手的回包,从而建立了一个不可靠的连接?
而杠精之所以是杠精,就是因为木有脑子。你考虑的问题,咱们祖师爷肯定都考虑到了。
我们在前面分析三次握手的过程的时候,为什么要强调ack = 上一次的seq+1?就是代表我不仅收到了你的,我还在你的seq上加1,代表我收到的确实是你的消息,这就相当于给这条消息打上了独一无二的标志,别人想鱼目混珠都不可能。
最后,咱们说说,三体人和叶文杰建立的是TCP连接吗?咳咳,明显不是。本文只是举例类比。要知道,叶文杰第一个包可是broadcast,谁都能收到的。
全部0条评论
快来发表一下你的评论吧 !