这篇文章,是之前《小白必读:计算机网络入门》的续集,零基础介绍TCP协议。

你是一台电脑,你的名字叫 A

经过《小白必读:计算机网络入门》这篇文章中的一番折腾,你会知道:只要你有另一位伙伴 B 的 IP 地址,且你们之间的网络是通的,那么,无论多远,你都可以将一个数据包发送给他。

这就是物理层、数据链路层、网络层这三层所做的事情。

站在第四层的你,可以利用下三层所做的铺垫,随心所欲地发送数据,而不必担心找不到对方。

此时的你,给自己这一层起了个响亮的名字,叫做传输层

你本以为自己啥事都没有,但问题很快接踵而至。

问题来了

前三层协议只能把数据包从一个主机搬到另外一台主机,但是,到了目的地以后,数据包具体交给哪个程序(进程)呢?

所以,你需要把通信的进程区分开来,于是就给每个进程分配一个数字编号,你给它起了一个响亮的名字:端口号

然后你在要发送的数据包上,增加了传输层的头部,源端口号目标端口号

OK,这样你将原本主机到主机的通信,升级为了进程和进程之间的通信

你没有意识到,这就是 UDP 协议

(当然 ,UDP 协议中不光有源端口和目标端口,还有数据包长度和校验值,我们暂且略过)

就这样,你用 UDP 协议无忧无虑地同 B 进行着通信,一直没发生什么问题。

但很快,你发现事情变得非常复杂......

丢包问题

由于网络的不可靠,数据包可能在半路丢失,而 A 和 B 却无法察觉。

对于丢包问题,只要解决两个事就好了。

第一个,A 怎么知道包丢了?

答案:让 B 告诉 A

第二个,丢了的包怎么办?

答案:重传

于是你设计了如下方案,A 每发一个包,都必须收到来自 B 的确认(ACK),再发下一个,否则在一定时间内没有收到确认,就重传这个包。

你管它叫停止等待协议

只要严格按照这个协议执行,虽然 A 无法保证 B 一定能收到包,但 A 能够确认 B 是否收到了包,收不到就重试,尽最大努力让这个通信过程变得可靠。

于是,你们现在的通信过程又有了一个新的特征——可靠交付

效率问题

停止等待虽然能解决问题,但是效率太低了,A 原本可以在发完第一个数据包之后立刻开始发第二个数据包,但由于停止等待协议,A 必须等数据包到达了 B ,且 B 的 ACK 包又回到了 A,才可以继续发第二个数据包,这效率慢得可不是一点两点。

于是你对这个过程进行了改进,采用流水线的方式,不再傻傻地等。

顺序问题

效率是提升了。但是,网络是复杂的、不可靠的。

有的时候 A 发出去的数据包,分别走了不同的路由到达 B,可能无法保证和发送数据包时一样的顺序。

在流水线中有多个数据包和ACK包在乱序流动,他们之间对应关系就乱掉了。

这该怎么办呢?办法如下:

A 在发送的数据包中增加一个序号(seq),同时 B 要在 ACK 包上增加一个确认号(ack),这样不但解决了停止等待协议的效率问题,也通过这样标序号的方式解决了顺序问题。

而 B 这个确认号意味深长:比如 B 发了一个确认号为 ack = 3,它不仅仅表示 A 发送的序号为 2 的包收到了,还表示 2 之前的数据包都收到了。这种方式叫累计确认累计应答

(注意:实际上 ack 的号是收到的最后一个数据包的序号 seq + 1,也就是告诉对方下一个应该发的序号是多少。但图中为了便于理解,ack 就表示收到的那个序号,不必纠结。)

流量问题

有的时候,A 发送数据包的速度太快,而 B 的接收能力不够,但 B 却没有告知 A 这个情况。

怎么解决呢?

很简单,B 告诉 A 自己的接收能力。A 根据 B 的接收能力,控制自己的发送速率,就好了。

B 怎么告诉 A 呢?B 跟 A 说"我很强"这三个字么?那肯定不行,得有一个严谨的规范。

于是 B 决定,每次发送数据包给 A 时,顺带传过来一个值,叫窗口大小(win),这个值就表示 B 的接收能力。同理,每次 A 给 B 发包时也带上自己的窗口大小,表示 A 的接收能力。

B 告诉了 A 自己的窗口大小值,A 怎么利用它去做 A 这边发包的流量控制呢?

很简单,假如 B 给 A 传过来的窗口大小 win = 5,那 A 根据这个值,把自己要发送的数据分成这么几类。

图片过于清晰,就不再文字解释了。

当 A 不断发送数据包时,已发送的最后一个序号就往右移动,直到碰到了窗口的上边界,此时 A 就无法继续发包,达到了流量控制。

但是当 A 不断发包的同时,A 也会收到来自 B 的确认包,此时整个窗口会往右移动,因此上边界也往右移动,A 就能发更多的数据包了。

以上都是在窗口大小不变的情况下,而 B 在发给 A 的 ACK 包中,每一个都可以重新设置一个新的窗口大小,如果 A 收到了一个新的窗口大小值,A 会随之调整。

如果 A 收到了比原窗口值更大的窗口大小,比如 win = 6,则 A 会直接将窗口上边界向右移动 1 个单位。

如果 A 收到了比原窗口值小的窗口大小,比如 win = 4,则 A 暂时不会改变窗口大小,更不会将窗口上边界向左移动,而是等着 ACK 的到来,不断将左边界向右移动,直到窗口大小值收缩到新大小为止。

OK,终于将流量控制问题解决得差不多了,你看着上面一个个小动图,给这个窗口起了一个更生动的名字,滑动窗口

拥塞问题

但有的时候,不是 B 的接受能力不够,而是网络不太好,造成了网络拥塞

拥塞控制与流量控制有些像,但流量控制是受 B 的接收能力影响,而拥塞控制是受网络环境的影响。

拥塞控制的解决办法依然是通过设置一定的窗口大小。只不过,流量控制的窗口大小是 B 直接告诉 A 的,而拥塞控制的窗口大小按理说就应该是网络环境主动告诉 A。

但网络环境怎么可能主动告诉 A 呢?只能 A 单方面通过试探,不断感知网络环境的好坏,进而确定自己的拥塞窗口的大小。

拥塞窗口大小的计算有很多复杂的算法,就不在本文中展开了,假如拥塞窗口的大小为  cwnd,上一部分流量控制的滑动窗口的大小为 rwnd,那么窗口的右边界受这两个值共同的影响,需要取它俩的最小值

窗口大小 = min(cwnd, rwnd)

含义很容易理解,当 B 的接受能力比较差时,即使网络非常通畅,A 也需要根据 B 的接收能力限制自己的发送窗口。当网络环境比较差时,即使 B 有很强的接收能力,A 也要根据网络的拥塞情况来限制自己的发送窗口。

连接问题

有的时候,B 主机的相应进程还没有准备好或是挂掉了,A 就开始发送数据包,导致了浪费。

这个问题在于,A 在跟 B 通信之前,没有事先确认 B 是否已经准备好,就开始发了一连串的信息。就好比你和另一个人打电话,你还没有"喂"一下确认对方有没有在听,你就巴拉巴拉说了一堆。

这个问题该怎么解决呢?

地球人都知道,三次握手嘛!

A:我准备好了(SYN)

B:我知道了(ACK),我也准备好了(SYN)

A:我知道了(ACK)

A 与 B 各自在内存中维护着自己的状态变量,三次握手之后,双方的状态都变成了连接已建立(ESTABLISHED)。

虽然就只是发了三次数据包,并且在各自的内存中维护了状态变量,但这么说总觉得太 low,你看这个过程相当于双方建立连接的过程,于是你灵机一动,就叫它面向连接吧。

注意:这个连接是虚拟的,是由 A 和 B 这两个终端共同维护的,在网络中的设备根本就不知道连接这回事儿!

但凡事有始就有终,有了建立连接的过程,就要考虑释放连接的过程,又是地球人都知道,四次挥手嘛!

A:再见,我要关闭了(FIN)

B:我知道了(ACK)

给 B 一段时间把自己的事情处理完...

B:再见,我要关闭了(FIN)

A:我知道了(ACK)

总结

以上讲述的,就是 TCP 协议的核心思想,上面过程中需要传输的信息,就体现在 TCP 协议的头部,这里放上最常见的 TCP 协议头解读的图。

不知道你现在再看下面这句话,是否能理解:

TCP 是

面向连接的、可靠的、基于字节流的

传输层通信协议

面向连接、可靠,这两个词通过上面的讲述很容易理解,那什么叫做基于字节流呢?

很简单,TCP 在建立连接时,需要告诉对方 MSS(最大报文段大小)。

也就是说,如果要发送的数据很大,在 TCP 层是需要按照 MSS 来切割成一个个的 TCP 报文段 的。

切割的时候我才不管你原来的数据表示什么意思,需要在哪里断句啥的,我就把它当成一串毫无意义的字节,在我想要切割的地方咔嚓就来一刀,标上序号,只要接收方再根据这个序号拼成最终想要的完整数据就行了。

在我 TCP 传输这里,我就把它当做一个个的字节,也就是基于字节流的含义了。

后记

一提到 TCP,可能很多人都想起被“三次握手”和“四次挥手”所支配的恐惧。

其实,你跟着文中的思路就会发现,“三次握手”和“四次挥手”只占 TCP 所解决的核心问题中很小的一部分。只是因为它在面试中很适合作为知识点进行考察,所以在很多人的印象中就好像 TCP 的核心就是握手和挥手似的。

本文希望你能从问题出发,真正理解 TCP 所想要解决的问题,你会发现很多原理就好像生活常识一样顺其自然,并不复杂,希望你有收获。

续集来啦!小白必读:什么是TCP?相关推荐

  1. 十大被低估的python库_小白必读!十大被低估的Python自带库!

    原标题:小白必读!十大被低估的Python自带库! 大家在学习python的过程中,都会了解到python的一个强大的功能在于各种强大的第三方库函数,大家只需要通过pip install 即可安装我们 ...

  2. 全网推荐的理财小白必读书目《小狗钱钱》,有那么好吗?

    既然今天说的是书,那么我们先一起思考一个问题吧,什么样的书算是一本好书?其实这个问题跟什么样的饭算一顿好饭是一个道理. 不同的人,在不同的人生阶段对一本书是好是坏的评价标准一定是不同的,想考专八的人, ...

  3. 耳机接口规则_耳机小白必读 一分钟看懂什么是TRS接口

    新酷产品第一时间免费试玩,还有众多优质达人分享独到生活经验,快来新浪众测,体验各领域最前沿.最有趣.最好玩的产品吧~!下载客户端还能获得专享福利哦! 当我们在使用数码音频产品时,往往面对的第一件事情就 ...

  4. 小白必读~内网渗透之信息搜集(2)

    初学者必读:信息搜集第二篇 到此一聚,不妨点个赞关注一下!!!嘻嘻 上次讲到 敏感信息收集** 接着继续 go go go 邮箱信息收集 收集邮箱信息主要有两个作用:1.通过发现目标系统账号的命名规律 ...

  5. 音频的音量检测java实现_免费剪切和合并音频,小白必读

    对于音频小白来说,想把MP3等格式的音频丢弃剪切掉一部分,真的太难了:如果想把两段音频合并成一个音频,更是难上加难.这个时候,我们可能会在网上去寻找一些软件,网上软件又良莠不齐,摸不准到底哪个能实现自 ...

  6. 【小白必读】机器学习入门须知

    一.机器学习入门浅谈 机器学习领域,又或者更大而化之的说人工智能方向,因为"阿尔法狗"等一系列的热门爆点话题,被推到了人前,受到越来越多人的关注. 无论你是什么领域的工作者,都一定 ...

  7. 币圈小白必读的6本加密货币书籍

    刚入币圈或者想入还未进入币圈的小白盆友,对这个行业知之甚少,如果想快速获取加密货币相关信息,网上阅读相关指南.相关专业文章是不错的选择. 如果不喜欢长时间盯着手机或者电脑屏幕,书是不错的选择.下面给大 ...

  8. 【自媒体小白必读】自媒体赚钱:自媒体怎么赚钱,新手做自媒体怎么赚钱,自媒体怎么赚钱快!

    在越来越多的小伙伴们开始做自媒体,因为现在是自媒体时代.大家都赶上自媒体的风口,所有人都想在自媒体领域分上一杯羹.我觉得这种想法是正确的,只有与时俱进才不会被时代所淘汰.现如今在这个快节奏的时代,互联 ...

  9. 这可能是简易的机器学习入门(小白必读)

    本文用浅显易懂的语言精准概括了机器学习的相关知识,内容全面,总结到位,剖析了机器学习的what,who,when, where, how,以及why等相关问题.从机器学习的概念,到机器学习的发展史,再 ...

最新文章

  1. hashmap value占用空间大小_求比HashMap占用内存少的查找方法
  2. pupload 文件分块 php,基于Plupload实现Base64分割的文件上传方案
  3. destoon 短信发送函数及短信接口修改
  4. Atitit 战略之道 attilax著 v4 r88
  5. Sql server中 如何用sql语句创建视图
  6. regsvr32注册dll或ocx错误0x80040201的原因
  7. Spring常见问题解决 - Required request body is missing
  8. 《投资中最简单的事》”第二部分--投资办法“读书笔记
  9. mybatis 一对一、一对多、多对一、多对多
  10. CRC碰撞概率 与CRC校验长度的理解
  11. phpstorm安装jquery插件库
  12. 在sublime中插入图片
  13. Android下载并打开PDF文件
  14. 智慧校园人员定位系统解决方案
  15. 李岳恒: 区块链媒体的罗生门:要不要做APP?
  16. Android VideoView播放网络视频简介
  17. linux内核看门狗关闭方法,详解linux 看门狗驱动编写
  18. 北京大学2016年数学分析考研试题
  19. 中兴第一次对外发布4G LTE的M2M模块---ESM
  20. 永久免费开源在线客服系统推荐收藏

热门文章

  1. Cadence PCB仿真使用Allegro PCB SI生成串扰总结报告Crosstalk Summary Report及报告导读图文教程
  2. 端口3306 mysql命令_Mysql数据库非3306端口命令连接数据库解决方法
  3. 在云计算上,华为有什么作为
  4. 大小端(网络字节序)等概念
  5. 豆神教育轻装上阵,搏命“大语文”下能否扭转24亿亏损的乾坤?
  6. 药物四大专题专享限时报一送一(CADD+AIDD+AMBER+GROMACS)
  7. 1481_人月神话阅读笔记_焦油坑
  8. 多层多数据库模式开发的实验(五)数据层-Access数据库
  9. 手机app兼容性测试点分析(通用)
  10. Houdini 18入门篇