这是我参与更文挑战的第8天,活动详情查看: 更文挑战
前言
文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…
每篇一句
当你孤傲地站在黄金台上,不要忘了,这一刻所有的刃口都能指向你
絮叨
今天我们继续加油呀。
UDP协议:
讲完了 IP 层以后,接下来我们开始讲传输层。传输层里比较重要的两个协议,一个是 TCP,一个是 UDP。对于不从事底层开发的人员来讲,或者对于开发应用的人来讲,最常用的就是这两个协议。由于 面试的时候,这两个协议经常会被放在一起问,因而我在讲的时候,也会结合着来讲
TCP 和 UDP 有哪些区别?
一般面试的时候我问这两个协议的区别,大部分人会回答,TCP 是面向连接的,UDP 是面向无连接的。 什么叫面向连接,什么叫无连接呢?在互通之前,面向连接的协议会先建立连接。例如,TCP 会三次握 手,而 UDP 不会。为什么要建立连接呢?你 TCP 三次握手,我 UDP 也可以发三个包玩玩,有什么区 别吗?
所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态, 用这样的数据结构来保证所谓的面向连接的特性。
例如,TCP 提供可靠交付。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。我们 都知道 IP 包是没有任何可靠性保证的,一旦发出去,就像西天取经,走丢了、被妖怪吃了,都只能随它 去。但是 TCP 号称能做到那个连接维护的程序做的事情,这个下两节我会详细描述。而UDP 继承了 IP 包的特性,不保证不丢失,不保证按顺序到达。
再如,TCP 是面向字节流的。发送的时候发的是一个流,没头没尾。IP 包可不是一个流,而是一个个的 IP 包。之所以变成了流,这也是 TCP 自己的状态维护做的事情。而UDP 继承了 IP 的特性,基于数据报 的,一个一个地发,一个一个地收。
还有TCP 是可以有拥塞控制的。它意识到包丢弃了或者网络的环境不好了,就会根据情况调整自己的行 为,看看是不是发快了,要不要发慢点。UDP 就不会,应用让我发,我就发,管它洪水滔天。
因而TCP 其实是一个有状态服务,通俗地讲就是有脑子的,里面精确地记着发送了没有,接收到没有, 发送到哪个了,应该接收哪个了,错一点儿都不行。而UDP 则是无状态服务。通俗地说是没脑子的,天 真无邪的,发出去就发出去了
我们可以这样比喻,如果 MAC 层定义了本地局域网的传输行为,IP 层定义了整个网络端到端的传输行 为,这两层基本定义了这样的基因:网络传输是以包为单位的,二层叫帧,网络层叫包,传输层叫段。 我们笼统地称为包。包单独传输,自行选路,在不同的设备封装解封装,不保证到达。基于这个基因, 生下来的孩子 UDP 完全继承了这些特性,几乎没有自己的思想
UDP 包头是什么样的?
我们来看一下 UDP 包头
前面章节我已经讲过包的传输过程,这里不再赘述。当我发送的 UDP 包到达目标机器后,发现 MAC 地 址匹配,于是就取下来,将剩下的包传给处理 IP 层的代码。把 IP 头取下来,发现目标 IP 匹配,接下来 呢?这里面的数据包是给谁呢?
发送的时候,我知道我发的是一个 UDP 的包,收到的那台机器咋知道的呢?所以在 IP 头里面有个 8 位 协议,这里会存放,数据里面到底是 TCP 还是 UDP,当然这里是 UDP。于是,如果我们知道 UDP 头 的格式,就能从数据里面,将它解析出来。解析出来以后呢?数据给谁处理呢?
无论应用程序写的使用 TCP 传数据,还是 UDP 传数据,都要监听一个端口。正是这个端口,用来区分 应用程序,要不说端口不能冲突呢。两个应用监听一个端口,到时候包给谁呀?所以,按理说,无论是 TCP 还是 UDP 包头里面应该有端口号,根据端口号,将数据交给相应的应用程序。
当我们看到 UDP 包头的时候,发现的确有端口号,有源端口号和目标端口号。因为是两端通信嘛,这很 好理解。但是你还会发现,UDP 除了端口号,再没有其他的了。和下两节要讲的 TCP 头比起来,这个 简直简单得一塌糊涂啊!
UDP 就像小孩子一样,有以下这些特点:
- 第一,沟通简单,不需要一肚子花花肠子(大量的数据结构、处理逻辑、包头字段)。前提是它相信网 络世界是美好的,秉承性善论,相信网络通路默认就是很容易送达的,不容易被丢弃的。
- 第二,轻信他人。它不会建立连接,虽然有端口号,但是监听在这个地方,谁都可以传给他数据,他也 可以传给任何人数据,甚至可以同时传给多个人数据。
- 第三,愣头青,做事不懂权变。不知道什么时候该坚持,什么时候该退让。它不会根据网络的情况进行 发包的拥塞控制,无论网络丢包丢成啥样了,它该怎么发还怎么发。
TCP协议
上一节,我们讲的 UDP,基本上包括了传输层所必须的端口字段。它就像我们小时候一样简单,相 信“网之初,性本善,不丢包,不乱序”。
后来呢,我们都慢慢长大,了解了社会的残酷,变得复杂而成熟,就像 TCP 协议一样。它之所以这么复 杂,那是因为它秉承的是“性恶论”。它天然认为网络环境是恶劣的,丢包、乱序、重传,拥塞都是常 有的事情,一言不合就可能送达不了,因而要从算法层面来保证可靠性。
TCP 包头格式 我们先来看 TCP 头的格式。从这个图上可以看出,它比 UDP 复杂得多
首先,源端口号和目标端口号是不可少的,这一点和 UDP 是一样的。如果没有这两个端口号。数据就不 知道应该发给哪个应用。
接下来是包的序号。为什么要给包编号呢?当然是为了解决乱序的问题。不编好号怎么确认哪个应该先 来,哪个应该后到呢。编号是为了解决乱序问题。既然是社会老司机,做事当然要稳重,一件件来,面 临再复杂的情况,也临危不乱
还应该有的就是确认序号。发出去的包应该有确认,要不然我怎么知道对方有没有收到呢?如果没有收 到就应该重新发送,直到送达。这个可以解决不丢包的问题。作为老司机,做事当然要靠谱,答应了就 要做到,暂时做不到也要有个回复
TCP 是靠谱的协议,但是这不能说明它面临的网络环境好。从 IP 层面来讲,如果网络状况的确那么差, 是没有任何可靠性保证的,而作为 IP 的上一层 TCP 也无能为力,唯一能做的就是更加努力,不断重 传,通过各种算法保证。也就是说,对于 TCP 来讲,IP 层你丢不丢包,我管不着,但是我在我的层面 上,会努力保证可靠性。
这有点像如果你在北京,和客户约十点见面,那么你应该清楚堵车是常态,你干预不了,也控制不了, 你唯一能做的就是早走。打车不行就改乘地铁,尽力不失约。
接下来有一些状态位。例如 SYN 是发起一个连接,ACK 是回复,RST 是重新连接,FIN 是结束连接 等。TCP 是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变 更
不像小时候,随便一个不认识的小朋友都能玩在一起,人大了,就变得礼貌,优雅而警觉,人与人遇到 会互相热情的寒暄,离开会不舍的道别,但是人与人之间的信任会经过多次交互才能建立。
还有一个重要的就是窗口大小。TCP 要做流量控制,通信双方各声明一个窗口,标识自己当前能够的处 理能力,别发送的太快,撑死我,也别发的太慢,饿死我。
作为老司机,做事情要有分寸,待人要把握尺度,既能适当提出自己的要求,又不强人所难。除了做流 量控制以外,TCP 还会做拥塞控制,对于真正的通路堵车不堵车,它无能为力,唯一能做的就是控制自 己,也即控制发送的速度。不能改变世界,就改变自己嘛。
作为老司机,要会自我控制,知进退,知道什么时候应该坚持,什么时候应该让步。 通过对 TCP 头的解析,我们知道要掌握 TCP 协议,重点应该关注以下几个问题:-
- 顺序问题 ,稳重不乱;
- 丢包问题,承诺靠谱;
- 连接维护,有始有终;
- 流量控制,把握分寸;
- 拥塞控制,知进知退。