目录
一.UDP协议
要了解UDP协议,就先理解协议的报文格式.拼装报头的过程,就是所谓的""封装"".
UDP长度:即整个UDP数据报的长度(报头+载荷),该长度是使用两个字节的 长度来表示的,两个字节能表示的数据范围为0~65535,即一个数据报最大就是64kb,不能超过这个大小,一旦超过可能就会造成数据丢失,后果比较严重.
如何避免一个数据报的大小超过64kb呢?
两个方案: 1.在应用层代码中,对广告数据进行切分,分成多个UDP数据报,返回给上游的服务器,虽然可行,但是太麻烦了.因为在应用层进行拆分根合并是不容易实现的,并且很容易引出一些bug. 并且可能会存在:后发先至"的情况",假设发生数据为1,2,3三个数据,但在接受端收到的数据可能是1,2,3,也可能是3,2,1这个顺序,这就造成了很大的麻烦.这中方法不推荐 2.直接改成TCP来实现 TCP在网络传输对数据的长度是没有限制的.
UDP校验和
在网络上传输数据,是可能会出现一些问题的.网络上传输的数据本质是一些0/1bit流,这些bit流通过光信号或者电信号来表示的. 如果传输过程 收到一些干扰,就 容易出现“比特翻转”的情况(0->1,1->0),而校验和就是为了验证当前的数据是否出现了问题
校验和是会变的,例如:买了一种菜的时候校验和是1,两中菜校验和就是2.与校验和一样不一定是正确的,但是与校验和不一样就一定不正确.
校验和往往是通过原始数据 的 内容生成的,不同的内容生成的校验和就不一样.一旦数据发生变化,校验和就不一样.就可以通过校验和来判断当前的数据是否发生了变化.
实现校验和的算法有很多,常见的有:crc,md5.
二.TCP协议
TCP协议段格式

有关TCP的特性: 1.有连接 2.可靠传输 3.面向字节流 4.全双工
2.1保证可靠的核心
2.1.1确认应答
发送方发送数据给接受方了,接收方回应一个应答报文.如果发送方收到了这个应答报文就说明接收方收到了数据的.

由于网络上的传输,接受到的顺序是不确定的,因此不能就单纯的按照通过收到的顺序来确定逻辑.因此此处引入了序号和确认序号,即在协议格式中出现的序号和确认序号.

那么此时即使接受到的顺序,有着序号和确认序号就不会混乱了.
因为实际上,TCP传输数据是不论条的,是论字节的(面向字节流),因此序号和确认序号就是以字节为单位进行编号的.

编号是针对每个字节进行编号,依次进行累加.而且实际上序号的起始不一定是从1开始的.假设第一个请求,A给B发生了1000个字节的数据,序号就是1-1000,长度为1000,因此确认应答数据报的确认序号就是1001.意思就是,1001之前的数据,B已经收到了,另外,也可以理解成B在向A索要1001开始的数据。
发生方就可以根据确认的应答报文来确定接受方是否收到。只要发送方收到了应答,就认为接受方收到了,可靠传输就完成了。
2.1.2 超时重传
不可否认,确认应答机制是在数据传输比较顺利的情况来实现的。但在传输的过程 中可能会出现丢包。一旦数据丢包,就要进入超时重传的机制中了。

这两种情况,发送方无法区分,当前的发的数据丢了,还是应答数据丢了。发送方没有收到应答报文,那么能做到的事情就只能过段时间后重新发送信息。
要过段时间再发送的原因: 数据在 网络上传输是需要时间的,不是说这个数据刚发出去,就期望得到回应。可能要经过一段时间才能收到回应,但当没有收到应答报文,就会过段时间重新发送,具体多长时间,不同的系统实现方式不一样。
2.1.3 连接管理
连接管理说的就是,如何建立连接(三次握手),如何断开连接(四次握手)。这两个都是TCP中最高频的问题。是在内核上进行的。
三次握手:


本质上,就是A向B请求连接,B给予回应,B也向A请求连接,A也给予回应。这是四个步骤。但是B给予回应和B也向A请求连接可以合并为一个操作。
如果三次操作改为四次握手也不是不可以,只不过还要多设置一个数据报类型并且传输,因为服务器发送SYN和ACK都是在同一个时机,由操作系统内核完成。我们都知道网络传输这些数据报要涉及到封装和分用的,每一个数据报的封装和分用的步骤也是非常多的。而三次握手改为两次握手是不行的。
三次握手的目的: 1.投石问路:通过三次握手的过程,来确认A和B之间的传输是通畅的。尤其是要确认,A和B之间的各自的发送能力以及接受能力是否正常。
如果网络出现问题,此时三次握手都会难以成功,此时就没有必要进行后续的传输了。
2.协商参数:通过三次握手,让A和B之间协商,选择一些传输中合适的参数,如TCP的序号从几开始。
服务器两种关键的状态: 1.LISTEN:说明服务器已经启动,随时可以连接.当创建好了ServerSocket实例后,就进入了listen 2.ESTABLISHED:说明服务器和客户端的接受和发送都没有问题,已经可以开始通信了,等同于代码中accept方法返回,得到一个clientSocket实例.
四次挥手:A是客户端,B是服务器

此处ACK和FIN不是同时发送的原因: ACK和FIN发送的时机是不一样的,ACK是由内核来完成发送的,服务器发送的FIN是由代码决定的.它是当服务器一收到客户端发送FIN后,就会立刻发送ACK了,而服务器发送FIN的时机有两种情况: 1.当代码中调用了client.close()方法,服务器才会发送FIN

2.表面上看是调用了socket.close()方法发送的FIN,本质上是内核里面释放了对应的PCB的文件描述符 如:虽然代码中没有调用close,但是socket对象被GC回收了,也是可能会关闭释放对应的文件描述符的.(这个操作没有那么及时),再比如:代码中虽然没有调用close,但是进程结束了,对应的PCB就会随之销毁,而PCB里面包含文件描述符表也被销毁了,进一步的文件描述符也被销毁了..就同样会触发FIN.
四次挥手的流程图及状态转移图:

主要是两种状态:
1.CLOSE_WAIT: 这个状态是服务器收到FIN后,进入的状态,等待用户调用close方法来发生FIN.
2.TIME_WAIT 表示客户端收到了FIN后进入了TIME_WAIT状态,这个状态的意义就是为了处理最后一个ACK的丢包.
问题一:假设,A收到FIN,并返回ACK后就断开连接,而不是进入TIME_WAIT状态会咋样?
答:假设此时的ACK丢包了,那么服务器就认为可能是自己发生的FIN丢包了, 就会一直超时重传,但是连接都断开了,再重传也没有任何意义.
因此即使是进程已经退出了(服务器调用close(方法))TIME_WAIT状态仍然会存在. TIME_WAIT也会等待一定的时间,如果一定的时间之内也没有FIN重传过来,才会真正的销毁.这一定的时间是2*MSL(网络传输之间最长的一次通信时间,在linux中默认是1min,但MSL也是可以支配的)
问题 二:如果服务器上出现了大量的CLOSE_WAIT是什么原因?
说明这是代码出现了BUG,没有调用到close方法.
如果服务器上出现了大量的TIME_WAIT,那么可能是代码的bug,但也不全是,主动发起FIN的一方会进入到TIME_WAT,就需要排查服务器是否应该主动断开连接.
哪方先断开连接,哪方就先进入TIME_WAIT,进程退出后,TIME_WAIT状态仍存在,TCP的连接也存在,如果让服务器先退出,服务器这边就会进入到TIME_WAIT状态(原来的连接占据着端口),接下来如果服务器立刻启动,新的进程会又尝试重新绑定这个端口.可能会存在端口绑定的 情况. 因此在TCP服务器的时候,都是先结束的客户端,后结束服务器.
当然,如果使用原生的socket来尝试上面操作,效果会非常明显,服务器会启动失败.但是java中socket一般来说第二次启动也是成功的.
四次挥手不一定是四次,也有可能是三次.因为有延时应答和捎带应答,虽然FIN和ACK不是同一时间的,但是经过延时和捎带应答的情况是有可能合并在一起的.
四次挥手也不一定会执行,它是一个正常断开的流程,实际上,有的时候TCP连接也会异常断开.
2.1.4滑动窗口
TCP不仅仅是为了保证可靠性,而且还尽可能地提高效率,其实可靠性和效率是矛盾的.TCP努力的在可靠性和效率是矛盾的.TCP努力的在可靠性的前提下,还做出了很多性能优化手段.
正常情况下建立连接:这个过程要花很长的时间来等主机B返回ACK,而等待的过程就严重影响到传输效率.

滑动窗口的方式建立连接:
设置一个窗口的大小来一次性发送一批SYN,一次又等待一波的ACK,把多组数据的ACK的等待时间重叠了起来 .

一次批量发的数据的长度,就 称为窗口的大小,如果没有批量发送数据的长度的限制,就容易造成窗口无限大,ACK就一顿乱发,此时就没有可靠性而言.
这个窗口的大小是要根据接收方处理数据的能力来配置的.如果窗口太大,那么没有可靠性;如果窗口太小,整体的效率就降低了.

当窗口范围为1001-5001,就说明发送方现在同时发送了1001-2000.2001-3000.3001-4000,4001-5000.此时就在同时等待四组数据的ACK.
假设2001这个ACK先到,发送方就知道1001-2000这个数据被接收方接收了,接下来就立刻发送5001-6000的数据.它能够仍然保证窗口的大小是4份数据,仍然保证是4份数据在等ACK.因此滑动窗口并不是把4份ACK都等到了才发送下一个数据,而是始终保持窗口的大小为一个固定值.
我们知道了网络传输可能会出现后发先至的情况,如2001,3001,4001,5001都在网络上传输,就不一定是2001先到,也可能是3001先到.确认序号也在这里体现了作用,确认序号表示,从序号之前的前面的数据就都被接受到了. 如:假设先收到了3001这个ACK,则说明,则说明1001-2000,2001-3000的数据都已经被对方收到了,此时2001的这个ACK收或不收已经不是关键了
如果在滑动窗口的场景中丢包了咋办? 情况一:接收方的数据包丢了

其实这个没什么关系,还是因为确认序号的原因.确认序号能够包含前面的数据是否被接受方接受到. 此时的2001这个ACK丢了,只要3001这个ACK不丢,就说明3001之前的数据都被接受方接收了.相当于1001-2000这个数据报也得到了一个确认应答.实际上,TCP为了提高效率,在滑动窗口下,并不会每一条数据都有ACK,会隔几条数据才有一个ACK.
情况二:发送方的数据报发送了丢包.

我们知道发送方如果数据丢包了,就会发送超时重传,而在滑动窗口下也会进行重传.那么接收方如何告诉发送方丢包了呢?
假设1001-2000的数据发生了丢包,那么接收方就不可能返回2001的ACK,因为是1001开始丢包,主机B就会一直索要1001,确认序号就会一直是1001,直到1001-2000的数据报在接收方收到为止. 即使后面的2001-3000.3001-4000.4001-5000的数据报都没有丢失,它们返回的ACK的确认应答也一直会提示索要1001,发生方如果连续看到了几次1001这个ACK,就知道了1001这个数据丢了.
上图中,当1001-2000的数据重传成功后,返回的ACK就转变为7001,即1001-7000的数据已经发生成功了,再去索要7001的数据报
实际上有一个接收缓冲区来接收先前收到的数据,收到的数据就会被缓冲区刷走,没有收到的就返回ACK的应答报文会一直在重复索要.
2.1.5 流量控制
它的针对滑动窗口的进一步补充,本质上就是在控制滑动窗口 的大小,窗口的大小决定了传输的效率,窗口越大,可靠性越低,资源开销越大.窗口越小,效率越低.
因此,流量控制是基于接收方的处理能力来限制窗口大小的.TCP这个传输的过程就类似于一个生产者---消费者模型:

主机A发送的数据到了主机B的接收缓冲区,此时主机A就是生产者:主机B的应用程序,通过 socket api来读取数据.被socket api读到的数据就从缓冲区删掉.应用程序就是消费者.接受缓冲区就是交易场所.
所说的窗口大小,就是指发送方(主机A)批量发多少数据,比如:主机A发的数据很快,窗口很大,此时接收缓冲区的数量也会增加的很快.如果主机B的应用程序从接收区读取数据的速度没有发送方发生的快,那么接收缓冲区就容易溢出.此时仍然不加任何限制,主机A就会按照一样的速度发送,新来的数据没有地方保存,就被内核丢了.
因此流量控制机制就是为了解决这个问题.根据接收方的处理能力(接收缓冲区的空余空间大小),来动态决定发送方的发送速率(控制窗口的大小).
假如此时的接收缓冲区大小为4000.

1-1000数据到达的时候,缓冲区里面有用了1000,还剩下3000,返回的ACK中就会把3000这个信息告诉发送发送方.发送方再次发送数据的时候,按照3000作为窗口大小来进行发送.TCP的报文格式中就有了16位窗口大小(接收缓冲区的剩余空间)的数据.

如果窗口大小为0(接收缓冲区这边满了),那么发送方就停止了吗?
此时发送方的确是不发送数据了,但是为了能够查询当前接收方的窗口大小,每隔一段时间就重新发送一个窗口探测包,通过窗口探测包(不传输具体的业务数据),接收方触发ACK,在这个ACK就能够知道当前窗口的大小了.
2.16拥塞控制
实际上,在主机A和主机B的传输过程中,并不是只考虑数据在主机A,主机B,接收缓冲区的大小等的运行速率,而在主机A和主机B之间,还有很多中间链路.

先使用一个比较小的窗口来传输数据,观察是否丢包. 如果丢包,就立即降低发送速率.如果没有丢包,就逐渐加大发送速率.通过这样的方式来逐渐实验出一个比较合适的窗口的大小.因此实际的窗口大小是在流量控制和拥塞控制中权衡窗口能取的大小的最小值.

上面这张图描述了拥塞控制中,窗口大小的变化规则.一开始如果没有丢包,窗口就按照指数增长的速度变大,由于刚开始的时候的窗口大小很小,因此按照指数来增长能快速地扩大窗口的大小.如果到达阈值,就从指数增长变为线性增长.
2.1.7延时应答
延时应答也是用调整窗口的大小的,用来提高效率的 机制.让窗口大小在保证可靠的基础上,能尽量再打一点.对于流量控制来说,窗口的大小是接收方的接收缓冲区的剩余空间的大小来决定的..
延时应答的场景是发送方与接收方发送窗口探测包后,接收方会过一段时间再返回ACK,在这段时间中接收方是在不断从接收缓冲区消耗数据的,因此延时应答的ACK相比流量控制的ACK里面告诉发送方的窗口大小更大,因此就能够增大下次发送方的发送数据数据量,就能提升传输效率.
4.1.8捎带应答
很多服务器和客户端的通信模式,很多都是"一问一答"的方式.

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给 服务器说了 “How are you”, 服务器也会给客户端回一个 “Fine, thank you”.这个时候ACK就可以搭顺风车 , 和服务器回应的 “Fine, thank you” 一起回给客户端
客户端和服务器之间的通信,有以下几种模型:
1.
一问一答:客户端发一个请求,服务器返回一个对应的响应
2.多问一答:上传文件
3.一问多答:下载文件
4.多问多答:直播~~串流
2.1.9 面向字节流(粘包问题)
在这种面向字节流的情况下,需要注意一个重要的问题:粘包问题.
例如:此时三份数据,而每个TCP数据包的payload部分是一个完整的应用层数据

接收方收到这些数据之后,进行分用,就会把这些数据部分,给放到数据缓冲区里面

当应用程序从接收缓冲区读数据的时候,就不知道从 那到那是一个完整的应用层的数据报了,应用程序此时只能看到接收缓冲区里面一个一个的字节,而无法区分当前接收缓冲区里面有多少个应用数据报,以及从哪到哪是一个完整的应用层数据报
解决粘包问题的方式:通过设置一个合理的 应用层协议来解决. 1.给应用层数据设定结束符/分隔符 2.给应用层数据设定长度. 两种方式的核心就是要明确应用层数据中,报和报之间的边界.
方式1:给应用层数据设定结束符/分隔符.

方式2:设定包的长度,约定每一个应用层数据报的前4个字节,存储数据报的长度.
粘包问题并不是TCP特有的问题,而且只要是面向字节流都存在类似的问题,这两种解决粘包问题的方案,在HTTP中也也所体现
而UDP中就没有这样的问题:

三.网络层
1.IP地址
1.IP报文格式的字段
IP报文格式:此处主要是介绍IPv4


同样地,IP报头就包含报文格式数据的上面全部部分,而数据就在IP载荷中
1.2 4位版本号
版本号就是指IPv4与IPv6的6,4表示的数字有0-15,而现在就只有两中版本号,并且是经过很多年后,IPv6才诞生.
1.3 4位首部长度
表示的是一个IP数据的报头部分的长度是多少,4位表示的就是0-15,单位是4个字节,是IP数据报的报头和负载的分界线
1.4 8位服务类型
3位优先权字段(已经弃用),4位TOS字段和1位保留字段(必须置为0),因此我们真正需要关注的就是中间的4位TOS字段.
在4位TOS字段中,必须只有一个为1.其他位都是0,不能有多个为同时是 1.
可选服务类型:最小延时,最大吞吐量,最高可靠性,最小成本.
1.5 16位总长度
16位表示的是两个字节,数据范围在0-65355,16位总长度记录的是整个IP数据报的总大小,即最大为64KB.
因此在我们联想到UDP中有个字段也是记录整个UDP数据报的长度,并且大小跟IP数据报相等,当时在分析UDP数据报的长度这么小,如何解决当一个数据长过UDP数据报的方案有两种: 第一种是对数据 进行切分,在应用层中再进行合并,但是不推荐,因为有后发先至的情况会出现,并且没有标识的方法, 第二种就使用TCP 而在IP数据报中,IP协议内置了分包组包功能.因此IP数据报中就引入了16位标识,3位标志,13位片偏移.
1.6 16位标识,3位标志,13位片偏移
如果一个数据太长,IP协议就会自动的拆成多个数据报,然后进行 传输,然后接收方就会重新进行组包.这三个字段就是辅助实现拆包组包的.
16位标识;相当于IP数据报的身份标识,如果是来自同一个IP数据报,那么它们的16位标识就想同.
3位标志:第一位保留(保留的意思是现在不用,但是还没想好说不定以后要用).第二位表示"禁止分片",第三位表示"更多分片".如果第三位为1,则表示这个分片就是最后一个分片.如果为0,则表示当前 不是最后一个分片,后面还有.
13位片偏移:就是描述当前这个报拆分后的报顺序.
1.7 8位生存时间
这个字段表示一个IP数据报最多在网络上存活多久,这个TTL不是时间概念,而且一个次数.每次经过一个路由器的转发,TTL就-1,直到TTL减为0就把数据丢弃.

1.8 8位协议
8位协议的作用是:当前数据报被接收方接收到之后,分用的时候,要把载荷里的内容全部交给传输层的那一层协议.分用的时候就要保证,载荷数据内容和接下来交给的协议相匹配.
如果接收方收到的数据之后,要进行解析,如果解析到载荷里面的数据报与当层协议不符,则会导致错误.
有一个问题:网络层需要指定将数据传给传输层的那个协议,为什么传输层中的UD[/TCP的数据报中没有8位协议这个参数呢? 其实是目的端口在传输层中指定了这件事情,因为应用层的协议太多了.除了典型的HTTP外,还有我们可以自定义的协议,因此协议的类型是有很多的,不可能--概括,因此目的端口就能把数据准确地传到对应的 应用程序上了.
1.9 16位首部校验和
这个校验和是类似于UDP的校验和,主要用的是crc这样的方法去校验,但是此处不同的是校验和首部就可以了.载荷部分交给了TCP和UDP自己去校验了.
1.10 32位源IP地址和32位目的IP地址
IP协议最主要的作用: 1.地址管理:能够通过一系列的规则,把网络设备的IP地址给描述出来. 2.路由选择:根据当下的源IP和目的IP,规格出一条合适的路径. 127.0.0.1使用三个点,把32位的整数分成了四份,每份占一个字节.
关于IP地址,它用32位整数来表示,大概有42亿9千万个,虽然数字看上去比较多,但是让每一台主机关联不同的IP地址,那么IP地址可能就不够用.
处理方式: 1.动态分配IP 一个设备连接网络了.就分配IP地址,反之就不分配.但是这种方式治标不治本,假设后面互联网发展更快,每人多台主机并且连网,那么IP地址肯定不够的.
2.NAT机制 
因此设定为,局域网内部的IP在局域网内不能重复,但是不同局域网可以使用重复的局域网IP.此时直接连接到广域网(外网)的路由器设备, 就会有一个外网IP.
NAT机制就是:当局域网内部的数据往广域网上发送的时候,此时路由器就会自动的把其中的源IP给替换了

NAT机制的作用就是:一个外网IP可以对应到很多台内网设备的IP地址,而每不同的局域网的IP地址又可以相同,数据的传输也没有问题,就能够使用重复的IP地址了.
NAT机制虽然解决了IP地址不够用的问题,但也引入了一些问题: 当我们在主机搭建一个服务器,它是自己的机器,只有局域网IP(内网IP)是可以重复的,其实主机就没法根据一个内网IP来找到该服务器,除非在同一个局域网里.
因此我们假设在局域网内部的主机在80端口上弄个服务器,只要有外网通过80端口来访问服务器IP,此时就可以通过内网穿透工具,把这个请求通过云服务器和局域网主机的TCP连接,直接转发到局域网主机的80端口上.
如果使用端口号+NAT机制来设定IP地址,那么是完全够用的,因为端口号是两个字节来表示,则约6w给端口号,即一个NAT设备最多可以支持6w多个连接,这一般还是够的.假设在极端情况下,每个外网就连接6w个设备,因此最多最多用端口号和NAT机制来表示的电脑有6w*42亿千万..
3.地址管理
网段划分(组建局域网 的时候非常关键的要点),它要求一个局域网的主机,网络号要相同,主机号不能相同,并且相邻的局域网的网络号必须不同.(一个路由器连接两个局域网,那么这两个局域网就是相连的).
把IP地址一分为二,前半部分为网络号,后半部分为主机号..划分网络号的方法:可以通过子网掩码来划分.

子网掩码非常有特点,左半部分都是1,后半部分都是0 ,之后把子网掩码的每一位与IP地址的每一位进行按位与,得到的结果就是网络号. 子网掩码不一定非得是255.255.255.0,这个是最常见的.网络划分本来本质就是对IP地址进行分类,当下主流的分类就是基于子网掩码的方式来划分.
4.路由选择
路由在计算机中是有很多含义的,此处的路由指的是IP协议中的路径划分功能,如:路由的选择的过程其实就是A和B间选择一条合适的路径,这个合适并不是一个很 容易权衡的事情,会综合考虑:路径的长短,通信的速度,设备开销的大小.

但IP协议的路由选择的具体的过程根地图里的规划是有很大的区别的.:IP协议的路由选择是 :数据到达某个路由器之后,这个路由器并不知道网络整体的环境(这个环境很复杂),这个路由器只是知道它附近的情况(它了解和它相邻的设备的情况). 因此IP协议的路由选择是一个"探索式"的过程.
路由器的存储空间是有限的,不可能通过一个路由器的路由表保存整个互联网环境的所有节点情况.因此采用逐渐寻路的方式是一个成本更低的方式.
路由器的路由表 里面描述 了啥样的IP从啥样的网络接口(WAN/LAN)传输.知道了从哪边出后,就知道了大概的方向.
4.数据链路层
负责的工作:两个相邻结点的传输 核心的协议:以太网(涉及数据链路层和物理层的协议)(平时平时用的网线,准确来说就是以太网线)
4.1以太网数据帧格式

4.2 目的地址和源地址
目的地址和源地址指的是mac地址,而不是IP地址,它们那个之间还是有很大的区别的,一个mac地址占6个字节,一个IP地址占4个字节.
4.3 类型
类型中就是上面以太网数据帧的类型选择,0800,0806,8035. 0800指的是数据里面存储的是IP数据报 ;0806指的是数据里面存储的 是ARR请求/应答;8035指的是数据里面存储的是RARR请求/应答.数据的长度不能小于46-1500字节.
4.4 帧尾
帧尾中就是crc校验和.防止数据在网络传输中发生错误的情况.
4.5 mac地址
mac地址是数据链路层的地址.6个字节,因此表示的范围比IP4的地址大的多.当前来看,mac地址是可以做到每个主机都是唯一的地址的.而mac地址是 写死的(网卡出厂的时候就被写死了),因此mac地址会运用到一些场景.
如:网络上,某个人入侵了别个人的主机,找到他就要锁定他在入侵的时候暴露了自己的mac地址. 游戏设定"不能多开",一个电脑开多个客户端是不行的,因此就根据mac地址来判断,如果发现两个账号对应的mac地址是同一个,就是多开,
mac地址是由16进制来表示的
主机A要给主机B传输一个数据报,略过应用层和传输层的封装过程,直接考虑网络层开始:

将上面的IP数据报继续封装,到达数据链路层,封装成 以太网数据帧.
注:以太网数据帧的报头装的源mac和目的mac,即主机A的mac和路由器1的mac,而IP数据报里面记录的是最起始和最终的IP地址.

接下来,路由器1转发上面的以太网数据帧给路由器2,这个转发 过程中,IP数据内容不变,以太网帧头变了

接下来,路由器2转发上面的以太网数据帧给主机B,相同地,IP数据报的内容不变,以太网帧头变了.
mac和IP地址看起来效果类似,但它们各司其职,IP站在全局,max站在具体的局部,通过它们不同功能来完成网络传输.
2.MTU
物理层其实就是存在这样的硬性限制的,对应的数据链路层的数据帧,是有 一定的范围的大小的.这个范围的指标就是MTU.往往MTU这个值比IP数据报的最大长度(64k)还会更小,当然,不同硬件介质对 MTU是不同的.
IP数据报的分包其实不是因为超过了IP的长度才分的包,而是因为超过了MTU才产生的分包.因此IP数据报的分包给了MTU的限制提供了具体的方案,因此最大 值就是以太网的最大传输单元了.

MTU对UDP的影响 ;因为UDP会因为MTU进行分包,如果传输 的过程中有一个丢包,那么接收方就会对整个数据报的重组失败.本来 UDP就没有可靠性,分包后的丢包率更大,因此对UDP的可靠性就会受到更大的影响.
MTU对TCP的影响:TCP中引入了一个MSS(最大消息长度),即没有达到这个MSS的长度就不用进行分包.
MTU和MSS的关系:
