TCP协议详细介绍:
TCP | 有连接 | 可靠连接 | 面向字节流 | 全双工 |
先给你们看一个TCP协议的报文格式~~它有点大,我就这样画出来了~不然是一整行
来让我解释一番~~~but, 这要结合TCP的特性啦!!!-------可靠性传输
32位序号,32位确认序号 | 1.确认应答 | |
4位首部长度, 保留(6位) |
| |
6个特殊标志位 | URG, ACK, PSH, RST, SYN, FIN | 分布其中 |
16位窗口大小 | 5.流量控制 | |
16位校验和 | 与UDP同 | |
16位紧急指针 | 与URG相关 不细说 |
TCP最最最重要的特性-可靠性传输!
Okk, 问题来了 什么算可靠传输?
数据顺利达到对方, 对方给了响应~~~
这其实专业一丢丢叫: 1.确认应答2.超时重传3.连接管理4.滑动窗口(效率)5.流量控制6.拥塞控制7.延时应答(效率)8.捎带应答(效率)9.面向字节流(注意事项)10.异常处理(可靠性的延伸) --- 别怕 这只是TCP冰山一角的十个特性而已
小明知道小芳看到了消息~~~1.确认应答
举栗子1~~~~讲ACK
- 又到了我举栗子的 show time了!! (关于小明与小芳的爱情故事 详情请移步https://blog.csdn.net/m0_63501066/article/details/127966669)
- 这天, 小明想请小芳吃饭~
小明 | 小芳 |
芳芳~~晚上要一起吃南方菜嘛 | |
我去接你~ | |
好啊~~ | |
不要~~我和同事一起 |
你看! 小明请吃饭, 那他怎么知道,小芳答应了他 -> 小芳回复他咯~~
好~上专业芝士
- 回复“好啊~~” -> “应答报文” -> 称ACK (6个特殊标志位)
- 普通报文 ACK 这一位0
- 应答报文 ACK 这一位1
举栗子2~~~~讲32位序号, 32位确认序号
- 网络传输嘛~~从UDP就感受到了吧 是可能会受到干扰的~~那小明与小芳的聊天会不会这样
小明 | 小芳 |
芳芳~~晚上要一起吃南方菜嘛 | |
我去接你~ | |
不要~~我和同事一起 | |
好啊~~ |
呐呐呐~这就是另一种含义啦,小明,小芳的感情!!!! 会不会受到冲击呢~~~不会,因为这是可靠传输!!!!! 我们有 32位确认序号 简单来说 不如看图~~
小明 | 小芳 |
芳芳~~晚上要一起吃南方菜嘛 (1) | |
我去接你~ (2) | |
不要~~我和同事一起 (2) | |
好啊~~ (1) |
好~上专业芝士
- 前提,在确认应答机制中,引入序号来保证不出现歧义
- 32位序号: 针对请求数据进行编号
- 32位确认序号: 只是针对应答(ACK)报文有效
- 那再说说,实际传输时的操作~ TCP是一个字节流协议,编号的时候,也是以字节为单位,进行编号~~~这这这不如看图
小明的消息没发过去~~~2.超时重传
举栗子1~~~~
呐呐呐 如果更惨呢,小芳根本没收到小明的消息
两种情况
1.小明的话没发过去
小明 | 小芳 |
芳芳~~晚上要一起吃南方菜嘛 | |
我去接你~ |
2.小芳的话没发过去
小明 | 小芳 |
芳芳~~晚上要一起吃南方菜嘛 | |
我去接你~ | |
不要~~我和同事一起 | |
好啊~~ |
- 两种情况,都是丢包了~~~
- 咱们用计算机的图就是这么描述~
- 小芳会不会觉得小明是个大笨蛋~~都回消息了,还要发~~
- 别慌,这两个人的爱情❤, 有去重(根据序号去重~)来守护
好~上专业芝士
- 接收方(小芳)因为丢失ACK 会导致收到重复的信息~~ -> TCP就针对相同消息进行去重(根据序号)
- 然后进行,超时重传 – 让没收到的部分,再发一次~~
- 哪哪哪, 多久超时重传一次?
- 思考一下,狼来了的故事, 根本没狼,你硬要叫人,那第一次人们1分钟到,第二次人们3分钟到,,,,,第N次,没人来了~~
- So-> 一样道理, 第一次出现丢包, 发送方 到达 超时时间阈值后, 进行重传, 如果还无响应, 会继续重传,但是 超时时间阈值 会比上一次长………..几次之后,会尝试重置TCP连接, 还连不上, 放弃~
小明和小芳能互相(不)发消息~~3.连接管理
举栗子1~~~~建立连接~~(小明&小芳建立一个相互认同的关系)
咱们就结合故事与芝士看这个part
三次握手
好叭~还是需要补充亿点芝士:
- SYN(6个特殊标志位)(同步报文段): 如果为1, 说明这是一个同步报文段(尝试和对方建立连接)(你要不要做我女票~叼花❀)
- 三次握手的意义是什么?
- `检查一下当前网络是否畅通
- `检查双方的通信能力~~~看上图蓝色字
- `协商一些重要的参数~~比如, 小明小芳要一起约会了~商量一下几点和地点~~~
- 棕色字体, 两个TCP状态的简单介绍~~是附赠芝士~~
举栗子2~~~~断开连接~~(小明&小芳取消相互认同的关系)(oh my god 我磕的cp掰了)(呜呜呜)(他们还能旧情复燃吗?)(这会是偶像剧的烂俗情节吗?不知道哎)
四次挥手
哎 很悲伤的四次挥手,那我们 先学点芝士吧~~
- FIN: 结束报文段~~记住了,小明小芳的分手故事 finally
建立连接和断开连接都看完了, 思考一下, 为什么三回握手能合并, 四次挥手不能???
三次握手: 小芳给小明发的 SYN ACK 都是内核触发的, 也就是立即发送
四次挥手: ACK是内核触发的, 但是 FIN 是应用程序显示调用socket的close方法触发的
提高效率的小明~~~4.滑动窗口
继续走故事~~
小明终于醒悟了, 他前女友小丽,虽然离婚了, 但是已经怀孕了, 她甚至还爱着那个男人~~(呜呜呜,为什么当初和小芳分手啊,这男人,可恶!)~~~他发现,他喜欢小芳的, 于是, 他和小丽断干净了关系, 去找小芳, 但是小芳不见他, 他就发消息, 他之前发一条消息, 小芳很快就回一条, 但是现在, 小芳对他爱答不理, 总不回消息, 于是 小明, 连环夺命发~~~~~
没收到小芳消息, 他也发, 就是发发发~~~(我压岁钱也能被这样就好了~)~~
来学芝士:
- 滑动窗口,就是为了亡羊补牢的提高效率, 之前确保可靠传输做了那么多的工作, 必然它的速度就慢, 于是利用,滑动窗口来提高.
- 具体实施, 类似小明做法, 之前, 发送方(A)大量的时间都消耗等待ACK -> 但是,不等ACK, 直接继续发消息,就可以提高效率~~ -> 每次都批量发送一波消息,在等一波ACK…
- 解释为什么叫滑动~(下面有说窗口)->看图~
- 那问题来了! 批量 有点抽象,具体说数字才能知道到底发多少啊~ -> 发少了,效率提高少,发多了接收方也反应不过来~~~so-> 这就要看 ”窗口大小” 了 ->也决定了效率提高多少 ->窗口无限大,不就嘎嘎发~~~
- 那丢包了, 怎么办? 一下子发那么多数据, 这可怎么找? ---
传的数据丢了 | 丢了数据报A却不知道,但是B回一直回复ACK索要丢的数据, A知道后会重发,只把丢了的重传就行(因为之后的数据报A发了,B也收到了~) --谁丢传谁 –“快速重传” |
ACK丢了 | 部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认, 因为后者包含前者 (比如 它回下一个是3001, 所以下一个是2001丢了也无所谓, 因为它能回下一个是3001, 就说明之前的都接收到了~~) |
不能光走效率,还要考虑一下小芳心情~~~5.流量控制
小明要是这么发, 那就babiq了, 本来就烦,还狂发??? 所以, 要做出限制, 可以发, 但是不要那么那么多~~~
他俩现在感情不好~不让我讲细节~咱们继续学芝士:
流量窗口就是在滑动窗口的基础上做出限制~~~限制发送方的窗口大小不要太大(小明发的信息不要太多)
问题来了,窗口大小多少合适? -- 问问接收方,看接收方觉得多少合适 (咳咳,我也不知道小明是最后怎么知道的,所以后续细节请自行脑部, 这是来自小芳的反制, 小明加油! 小心一步踏错, 万丈深渊)
那接收方的接收速率,如何进行量化? – 接收方使用接收缓冲区的剩余空间的大小, 来作为发送方发送速率(窗口大小)的参考值
16位窗口大小: 接收缓冲区剩余空间大小的值, (ACK为1的时候(应答报文)才有意义) ~~看下面的图, 窗口大小其实是动态变化的~~很聪明,很巧妙
当他俩的故事是一个场景,而你们看故事是另一个场景, 那么,请考虑一下我作为中间人的心情叭,我给你们传递他俩消息~我我我,我的效率也考虑考虑呗, 一个故事N条芝士,芝士片,芝士碎~~顶不住啊~~~~6.拥塞控制
简单来说,我更新效率高! 给你们讲故事就多, 那我卡bug了, 咱们就有缘再见了~~
来用专业一点的话说:--oh 芝士
- 刚才的, 流量控制, 只考虑了接收方的处理速率,那发送方就能为所欲为了??? 不不不, 还要考虑中间这些转发节点的情况~~~
- 这该怎么考虑?? -> 试探它的底线!!从小的开始, 逐渐变大, 如果丢包在变小…反复动态规划
- 所以具体来说: 慢启动(先发少量)-> 不丢包 放大拥塞窗口->开始先指数增长(翻倍)->达到阈值(系统配置) (防止翻的太快了, 一下超上限)线性增长 ->回到最初值(但是说,做出了改变,TCP改成了,回归到一个中间值) …
7.延时应答
哈哈哈哈,没故事,直接看芝士吧~
- 提高传输效率的机制,又是基于流量控制, 来引入的提高效率的机制 (就是尽量让窗口大一点)
- 核心思路: 趁着延时的时间, 让应用程序赶快消费一波数据, 我们从而获取一个, 更大的窗口大小 -> 效率提升
8.捎带应答
基于延时应答
应答+ACK 合二为一 内核处理的,应用程序调用的 socket的write方法把数据交给内核, 内核进行封装, 在发送 ---- 看不懂! 来 让我调出小明小芳聊天记录给你讲讲~~
9.面向字节流
这里存在一个典型问题 --- ''粘包问题'' ,那我们还是看故事
小明: ”我真的确认, 我现在走出来了, 所以, 能在给我一次机会吗? 我会……”
小芳:” 嗯,我需要思考一段时间”
呐呐呐,如果, 现在场景是, 我们不知道小芳句子的结束在哪里 是嗯 还是 时间, 如果只给小明传递了 嗯 好的babiq了~~~这对cp必be了
所以, 我们有别的机制来, 让他们的爱情❤不因为这个be
芝士!快学!别让磕的cp be掉~
- TCP自身对于应用层数据报是无法做区分的
- so 要想解决粘包问题, 就要在应用层协议这里进行区分
- 只要定义应用层数据协议的时候, 明确包和包之间的 ''边界'' 就可以了 ->典型办法,有两种
1. 通过分隔符, 比如约定使用 ; 作为包的结束标记 |
2. 通过指定包的长度, 比如在数据包的开头位置声明长度 |
10.异常处理
这这这,直接看吧~~就 自我理解一下
i)程序崩溃了 | 进程异常退出 | 操作系统会回收进程的资源, 包括释放文件描述符表, 这样的释放操作, 就相当于调用了对应的socket的close, 执行close就会触发FIN报文, 进一步开始四次挥手 |
ii)正常关机 | 通过菜单这种方式来关闭主机 和程序崩溃差不多 | 关机的时候, 系统会先强制结束所有的用户进程, 和上述的那个进程崩溃类似, 系统内核, 会进行文件描述符的释放操作, 进一步进行四次挥手 |
iii)主机掉电 | 非常突然, 猝不及防 | 1,掉电的是接收方, 发送方是不知道对面挂了, 继续发数据 -> 此时发的数据, 没有ACK了, 发送方触发超时重传, 重传几次之后, 仍然无应答, 尝试重置连接(复位报文段RST), 也会失败, 只能 ->放弃连接 2.掉电的是发送方, 此时接收方就等着 -> 接收方也不是干等, 等了一阵之后, 就会发送一个 ''心跳包'' 心跳包是周期性触发的, 只是一个简单的不携带任何业务数据的包, 存在的意义就是确认一下对方是否还在, 如果对方不返回心跳包, 说明心跳遗失了. 对方挂了 -> 放弃连接 |
iv)网线断开 | 情况同主机掉电 | 只不过通信双方的主机都好着, 这两端各自按照上述的两种情况分别进行 |
恭喜恭喜, 你看完了~我更完了~我们都很棒~嘿嘿嘿 冲!~~