前几天发了一个朋友圈,发现暗恋已久的女生给我点了个赞,于是我当晚辗转反侧、彻夜未眠!想着妹子是不是对我有感觉呢?不然怎么会突然给我点赞呢?要不趁机表个白?
于是第二天我在心中模拟了多次表白的话语,连呼吸都反复练习。
到了晚上,我拨通了妹子的微信语音,还没等对方开口我就按捺不住内心的想法,开始自说自话,一阵狂乱的表达…足足五分钟一气呵成,一切都是那么自然!
可是在我说完之后却半天都没有等到妹子的回应…过了好一会儿才听到对方的声音:“喂!喂!我这边信号不好,你刚刚在说啥我一句都没听到,我在跟我男朋友逛街呢…”。
我挂断了电话,我也对我这次失败的表白进行了深度的总结!原因就是因为我没有学好TCP!
如果我懂TCP,那我在表白之前至少要先问一句“在吗?”!先建立可靠的连接,确保连接正常才能开始表白!
如果我懂TCP,那我在我说话的过程中需要对方不断的确认,这样才能保证我说的每一句话对方都能听到!这样我才能表白成功!
所以一切都是因为我没有学好TCP,于是我走进了图书馆…
我们先来看下TCP的定义:
TCP全称为Transmission Control Protocol(传输控制协议),是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。
这里面每一个字我们都认识,但是连在一块就不是那么好理解了!那我们就提炼一些关键的词理解TCP的实现原理!
传输层
我们先讲传输层,因为可以从比较高的层面去看TCP,我们先看下经典的OSI七层网络参考模型:
当我们需要在网络上进行数据交换的时候,就需要经过这么几层。每一层都有相关落地的实现,可能我们平时在说到传输层的时候自然而然的就想到的TCP,但是TCP只是传输层的一种实现,其他比较常见的传输层协议还有UDP等!
抓个包来看看,让这几层更加具象!本文中所有的包都是通过postman发送请求,然后用wireShark来抓的!我们在postman中输入的域名,然后发送请求,wireshark就能抓到数据包了。
图上已经标明每一层与抓到的数据包对应的关系了!咦!我们上面不是说的7层网络参考模型么?为什么数据包只有5层呢?注意参考二字,7层模型是一个理论模型,实际的网络中往往都把应用层、会话层、表示层统为应用层!
什么是协议?
说到协议,就是双方共同遵守的一种约定!比如我写的这篇文章里,你能够看懂我写的每一个字并明白我的意思,那就是因为我们都遵循了汉语的语法,这本身也就是一种协议。还有比如我们写代码就必须按照规定的语法进行编写,这样编译器才能进行正确编译。
在计算机网络中也有很多协议,比如常见的应用层协议http、ftp、dns协议等等。常见的传输层协议有TCP、UDP等等…
其实这些协议都是发送方和接收方都在遵循的一种规范。如果我们遵循了其规范,也能成为协议的实现者,比如自己写一个web服务器处理用户请求。甚至我们还能自己规定一套协议,供别人使用!
TCP头部格式
我们前面说了协议的定义,那TCP协议肯定也有一定的规范咯!这样通信双方才能识别对方的数据报文,进行数据交换,我们先看下TCP的报文格式
TCP报文包含数据头和数据体,头部有5行的固定长度以及1行可变长度!图上前面5行就是固定长度!固定长度的每一行占有4个字节(32位)。因此头部固定长度就为5*4=20个字节!
面向连接怎么理解
从我表白失败的例子就能看到,我还未确保连接的正常就开始表白,导致我说完了对方却因为信号不好没有听到。如果我事先确保连接正常,就不会出现这样的情况了!我们前面说了TCP是面向连接的,那TCP是怎么面向连接的呢?
三次握手交代了什么?
没错,都是从握手开始!我们都知道,tcp建立连接需要经过三次握手,那每次握手都交代了什么呢?如果只进行两次握手行不行?我们先看一个电话接通的场景:
A:你好,你能听到吗? B:我能听到,你能听到吗? A:我也能听到。 |
在正式通话之前,为了确保通话的可靠,往往都需要经过上面的三次对话进行确认。那这三次对话是必须的吗?每一次对话的必要性又是什么呢?
A:你好,你能听到吗?(让B知道A能说话) B:我能听到,你能听到吗?(让A知道B能听到,且能说话) A:我也能听到。(让B知道A能听到) |
只有经过三次的对话,才能确认自己的声音能被对方听到且能听到对方的声音。这也才能开展后续的对话。这里我们就不得不祭出经典的三次握手图了:
我们依然发送请求,下面为三次握手的包:
在info那一栏,我们很明显的能看到发送的数据包头部有我们上面说到的那些标志位,还有Seq、Ack等头部信息,还有Win、MSS等头部选项数据!因此三次握手不仅仅是单纯建立连接,还会协商一些参数!
当我鼠标选择某一行时,如果这个数据包包含了对某个数据包的确认(也就是有ACK的标记),就能在对应的数据包的No列上面看到一个小勾勾,比如上面图中我鼠标选择的是第三次握手的数据包,在第二次握手的数据包前面就有个小勾勾。
为什么握手只需要三次而挥手需要四次?
通过三次握手,双方就建立了一个可靠的连接,就能进行数据的传输了!当数据传输完成,就得将连接关闭,因为连接也是一种资源!连接的关闭需要经过四次挥手!
为什么握手可以三次完成,但是挥手却需要四次呢?我偏要三次行不行?其实也没啥不可以的!比如下面的对话场景:
A:我说完了,你说完就挂电话吧! B:好嘞,我也说完了,可以挂电话了! A:好嘞,拜拜。 挂断…… |
这样三次对话就可以实现挥手了,但是在实际的网络中,当我发出一个请求的时候,可能服务器的响应体比较大,需要较长时间的传输!所以当客户端主动发起断开请求的时候,服务器先回应一个确认,等所有数据传输完毕后再发送服务器断开的请求。
A:我说完了,你说完就挂电话吧! B:好嘞… B:…… B:我也说完了,可以挂电话了 A:好嘞,拜拜 挂断…… |
所以大部分情况下都需要进行四次挥手!但是,在我个人的抓包实践中,也会有三次挥手就能完成断开连接的情况。
这里我们又不得不祭出经典的四次挥手图了:
我们看上面发送请求的挥手数据包:
可能大家在抓包的时候不能立马看到四次挥手的数据包!那是因为在HTTP1.1及之后,默认都开启了长连接!
也就是在一次请求之后,建立的连接并不会立马关闭,而是供后续的其他请求继续使用,以减少每次重新建立连接的资源消耗!
如果想发出请求后立马能抓到四次挥手的数据包,可以设置Http的头部Connection:close。这样每次发送请求都能看到完整的三次握手四次挥手的过程啦!
最后,不管你是转行也好,初学也罢,进阶也可,如果你想学编程~
——【值得关注】我的C/C++编程学习交流俱乐部!——
涉及:C语言、C++、windows编程、网络编程、QT界面开发、Linux编程、游戏编程、黑客等等......