目录
前言:
1.网络原理的理解
2.应用层
2.1自定义协议的约定
2.1.1确定要传输的信息
2.1.2确定数据的格式
3.传输层
3.1UDP
3.1.1UDP报文格式
3.2TCP
3.2.1确认应答
3.2.2超时重传
3.2.3连接管理
3.2.3.1三次握手
3.2.3.2四次挥手
3.2.4滑动窗口
3.2.5流量控制
3.2.6拥塞控制
3.2.7延时应答
3.2.8捎带应答
3.2.9面向字节流(粘包问题)
3.2.10异常处理(心跳包)
3.3TCP与UDP的差别
4.网络层
4.1IP协议
4.1.1地址管理
4.1.1.1动态分配IP地址
4.1.1.2NAT机制
4.1.1.3IPv6
4.1.2路由选择
4.2IP地址的组成
4.2.1IP地址分类(ABCDE)
4.2.2子网掩码
4.3特殊的IP地址
5.数据链路层/物理层
5.1以太网
结束语:
在上一节中小编主要是与大家讲述了有关于网络编程方面的知识,如果没有查看的同学请点击这里☞http://t.csdn.cn/zZ5wt ,接下来小编继续带着大家来看网络编程中的一些更深层次的一些知识,大家快快来和小编一起学起来吧!
我们之前学习了网络初识,这里面我们对网络有了大体的概念和认识,接下里学习了网络编程,在这里面主要是给大家介绍了UDP和TCP,让我们真正通过代码来感受到了网络通信程序,这里再给大家来介绍网络原理,让我们来进一步的了解网络的工作过程。下面我们将通过对网络协议分的这几层来分别给大家一一介绍,从应用层->传输层->网络层->数据链路层->物理层。这里主要的重点是应用层和传输层,其余的大家简单了解即可。
这里的应用层是简单给大家先介绍一下,在后期小编还会给大家出有关于HTTP的内容,这这块小编在给大家详细介绍一番。应用层和代码是直接相关的一层,它决定了数据要传输什么,拿到数据之后又该怎么使用。在应用层这里虽然存在一些现有的协议(HTTP),但是也有很多情况是需要程序猿来自定制协议的。关于自定制协议就是说要约定好应用层数据报,和数据格式,此时就是在自定义协议。那么我们具体的该如何进行约定呢?详细请看下面。
首先你要想传输数据就得先确定好你要传输的数据都有哪些,这里是根据需求文档走的,比如我现在要点一份外卖那么可能就需要下面的这些信息。
那么当上面确定好了要发送的数据之后,就要规定一下要发送的数据应该是以那种格式来进行发送。在网络上传输本质上都是0101的二进制字符串,此时我们需要把上述这些信息都整合成一个字符串。
这里有一个简单的方案就是直接使用分隔符来进行组织,当然也不是一定要使用分隔符,这里还是可以使用其他的符号来进行分隔的,我们可以让属性和属性之间使用\n来进行分隔。那么只要接收方按照这套格式来组织数据,接收方按照这套格式来解析数据,两者只要可以对的上,这样的格式就是可以的。
在实际开发中也有一些现成的格式可以直接使用,比如XML里面就是使用标签的形式来进行组织的,再比如现在比较流行的格式JSON,他是使用{}来进行组织的。
这些我们会在后面一一给大家讲解。
如下图所示:
下面来区分一下这几个概念:源IP、源端口、目的IP、目的端口。
这就几个就像是西游记里唐僧经常说的一句话:“贫僧自东土大唐而来,到西天拜佛取经”。这几个对应关系如下图所示:
在UDP报头中就会包含源端口,表明自己是从哪里来的数据,同时包含目的端口号,指明这些数据要到哪里去。
每个端口号在UDP中都占有两个字节,它的取值范围其实是0-65535。其中小于1024的称之为“知名端口号”,是给一些名气比较大的服务器预留的端口,这部分端口在咱们写代码的过程中不应该使用。就像是坐飞机的时候会分为头等舱和经济舱一样的道理,但是这里注意0这个端口虽然是合法的端口,但是实际上是没有人使用的。
他也是占2个字节的,范围是0-65535也就是64KB。所以一个UDP报文的最大长度就是64KB,这里我们可以看到64KB放在现在是一个很小的数字了,所以大家在使用UDP编程的时候一定要注意UDP的数据报不能够太长,否则的话就会出现问题。
在网络的传输中并不是那么的稳定,可能会出现各种各样的幺蛾子。通过网线传输的时候是电信号,电信号使用的是高低电频,用0 1 表示。但是如果外部环境干扰,比如强磁场之类的就可能会导致高电频变成了低电频,低电频变成了高电频,这就会导致传输的数据出现错误,那么此时就需要一个判定,判断一下传输的数据是不是正确的,这就是校验和存在的意义,它就是用来判定当前传输的数据是否出错。
举个例子:
比如现在父母让我们下楼买菜,要买西红柿、鸡蛋、茄子、芹菜。一共买四样菜,这里的买四样菜就是一种校验和,我们买完之后如果是四样,那么就说明这里是有可能是对的,但是如果是三样或者是五样菜,那么一定是买错了,注意这里小编在说买四样菜的时候为什么会说是可能是对的,因为数量首先是对的,但是可能买回来的菜的种类就不一样了呀!
所以说如果校验和不对,此时你的数据一定不对,但是校验和对,但是数据也是有可能是错的。
所以为了让校验和能够辨识率更高一些,计算的时候通常会以数据内容作为参数来进行计算,数据内容发生变化,校验和也就会发生变化。
在上一节中小编给大家大体介绍了一下TCP,它是有连接、可靠传输、面向字节流、全双工的。TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率,这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。那么这里的可靠传输就是TCP存在的初心,也是最核心的机制。那么这里TCP是如何实现的可靠传输的呢?下面给大家介绍可靠传输的十个机制:确认应答、超时重传、连接管理、滑动窗口、流量控制、拥塞控制、延时应答、捎带应答、面向字节流、异常处理。下面就来展开一一给大家叙述一下这十个机制。
确认应答是实现可靠传输最核心的机制。比如下面的传输机制。
当A主机给B主机发送了数据1000,然后此时B主机就给A主机返回一个应答报文,并告诉下一个要传输的数据是从1001开始的,此时A主机就会继续发送1001-2000的数据,B主机又会返回一个应答,并告诉下一个数据的开始时2001。
那么在网络上经常会出现后发先至的情况,比如A主机发送完0-1000数据之后,在发送1001-2000,此时B主机先返回了2001,再返回1001,此时就会出现问题,那么为了解决上述的问题,就需要针对消息进行编号,给发送消息分配一个“序号”,同时应答报文,给出“确认序号”。
这里确认应答发送的叫做ACK,每一个ACK都会带有确认列号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发送。
注意:
确认序号的规则:不是说发送方的序号是啥,确认序号就是啥,而是取的是发送方发过来的所有数据最后一个字节的下一个字节的序号。比如确认序号1001的含义:1.表示小于1001的数据我都已经收到了 。2.我接下来想向发送方索要从1001开始的数据。
在网络中会经常出现一种现象叫“丢包”。
情况一:数据直接丢了,接收方没有收到,自然就不会发送ACK。
情况二:接收方收到数据了,返回的ACK丢了。
主机A未收到B发来的确认应答,也可能是因为ACK丢失了。
那么什么会出现丢包问题呢?
在A主机和B主机之间还存在着很多中间的路由器...每个设备都在承担着很多的转发任务,每个设备的转发能力都是有上限的,某个时刻,某个设备,上面的流量达到峰值,就可能会引起部分数据包被丢失。如果包丢了,接收方就收不到了,自然就不会返回ACK了,发送方就会迟迟收不到应答报文,发送方就视为刚才的数据包丢了,就会重新再发一遍。
发送方对于丢包的判断是一定时间内没有收到ACK。
注意:
对于上是的情况二,B就会收到重复的数据,那么这里也不用我们担心,TCP这里会帮我们做好处理,他会在接收缓冲区中根据收到的数据的序号自动去重,这样就保证了应用程序读到的数据仍然只有一份。
解决丢包问题:
TCP建立连接是通过三次握手,TCP断开连接是通过四次挥手。那么下面我们就来具体看一下三次握手和四次挥手究竟是怎么一回事吧。
三次握手是TCP建立连接的一个过程。握手(handshake)是指通信双方,进行一次网络交互,相当于客户端和服务器之间,通过三次交互,建立了连接关系。
首先来明确两个概念:
下面我们来给大家画图来演示一下整个握手的过程:
这里又有同学好奇了,为什么在上述中明明客户端和服务器之间进行了四次交互,为什么要叫三次握手呢?因为这里的SYN和ACK是可以同时打包发送给客户端的。如果是打包同时发送给客户端的话就会变成三次交互,也就是三从握手了,如下图所示:
TCP三次握手具体流程如下所示:
上述的这几个都是特殊的比特位,这几个默认是0,如果设置为1,则表示特定的含义。
了解完三次握手之后我们还得了解一下为什么要三次握手,它起到了啥效果达到了啥目的呢?
三次握手这个过程本质上是在投石问路,它验证了客户端和服务器之间各自发送能力和接收能力是否正常。 这就像是我们在通话的时候先会确认一下对方和自己的的信号是否正常一样,
上面是三次握手是客户端与服务器之间建立连接,那么怎么断开来连接呢?我们这里是采用四次挥手,具体的我们来看下面的图所示:
四次挥手的具体流程如下所示:
这里小编给大家举一个例子来方便大家的理解。假如客户端和服务器是男女朋友的关系,此时他俩现在想要分手,那么女生就对男生说咱两分手吧(向另一方发送了FIN的请求),男生收到之后,给女生说我知道了(向另一方发送一个ACK包表示已经收到了请求),那么接下来男生说那就分手吧(再向另一方发送了FIN包,表示断开连接),此时女生收到这条分手消息之后,发个消息表示已经收到了(向另一方发送ACK包,表示已经接收到了)。
那么这里有一个问题就是上面在三次握手的时候中间的ACK和SYN可以合并一起发送,那么这里是不是也可以打包一起将FIN和ACK一起发送呢?会不会变成“三次挥手”呢?
答案是:否,首先这里需要明确一点三次握手中SYN和ACK是同一时机触发的,都是有内核来完成的,而四次挥手的ACK和FIN则是不同时机触发的,ACK内核完成的,会在收到FIN的时候第一时间返回,而FIN则是应用程序代码控制的,在调用到socket的close方法的时候才会触发FIN。所以是不可以合并的。
四次挥手的主要作用:
因此,TCP协议需要进行四次挥手,以确保双方都能正确的关闭连接,并避免数据的丢失和混淆。
TCP要保证的不仅仅是可靠性,还要保证效率,但是要提升效率往往意味着损失效率。如下所示的发送方式就是一种效率极其低的发送方式:
此时主机A这边就花了大量的时间在等待ACK,就相当于是发送快递,总不能是发送一个包裹,然后服务器等待客户端收到包裹然后再给下一个客户发送包裹吧,所以想要提高效率就得批量发送数据了,一次发送多条数据,一次等待多个ACK,如下所示:
上述就是一次批量发送了4条数据,发送完之后,统一等待ACK,每次收到一个ACK就立即发送下一条,上述批量传输数据的过程就称为“滑动窗口”。
批量并不是无限发送,而是发送到一定的程度,就等待ACK,不等待直接发送数据量是有上限的。而且是回来一个ACK就立即发下一条,相当于总的要等批量的数据是一致的。此时就把等待数据的数量就称为“窗口大小”。示意图如下所示:
所以此时看到的效果就像是窗口还会那么大,但是往后挪动了一个格子,如果收到的ACK非常快,此时这个窗口就在快速的往后滑动。
那么如果在发送的过程中,如果出现丢包咋办呢?那么此时就是要“可靠性第一,效率第二”。出现的情况可能有以下几种:
情况一:数据包已经到达,ACK被丢了。
在上述情况中相当于是一半的ACK都已经丢了,相当于是丢包率是非常的高,但是注意:这种情况下对于可靠性传输是没有任何影响的,因为确认序号的含义表示该序号之前的数据都已经收到了,后一个ACK,能够涵盖前一个ACK的意思。
假设现在是1001-2000这个数据丢失了,那么接收方就会继续索要1001,此时不会说是因为收到的是2001-3000就会返回3001,那么接下来几次的数据ACK确认序号都会是1001,也就是B在反复的向A索要1001这个数据,A这边收到之后,就知道事情不简单,就知道1001可能是丢失了,此时A就会重传1001-2000这个数据了。这就是重传过程,也叫快速重传。
流量控制也是保证可靠性的机制。上述的滑动窗口越大相当于批量发送的数据就会越多,整体的速度就会越快,但是真的是越快越好吗?如果发送的太快,那么就会瞬间把接收方的缓冲区给打满了,此时数据就会出现丢包,这种情况就得不偿失了,还不如发送的慢一点。那么怎么才能慢下来呢?这里就可以通过流量来进行控制,本质上就是让接收方来限制一下发送的速度,让发送的慢一点甚至阻塞一下。
具体在ACK报文中携带了一个“窗口大小”这样的字段。如下所示:
注意:上述的16位窗口大小只是建议发送的窗口大小,并不是在发送的时候就非要采纳这个值,那么接收方这里会计算出一个窗口大小的值, 那么究竟是如何计算的呢?它采用了一个简单粗暴的办法就是直接拿接收缓冲区剩余的空间作为窗口大小。
发送窗口的大小 = 流量控制 + 拥塞控制。
下面我们就来给大家讲解一下拥塞控制。
上述中讲解了流量控制,滑动窗口的大小主要就时取决于流量控制和拥塞控制的。流量控制主要是衡量了接收方的处理能力,而拥塞控制主要是衡量了传输路径的处理能力。
如下图所示:
在传输过程中数据并不是直接就能够从主机A传输到主机B的,而是通过中间若干个路由器和交换机等的传输,最终才能够到达主机B, 所以很明显,在传输的路径上任何一个设备处理能力如果遇到了瓶颈都会对整体的传输速率产生明显的影响。
而拥塞机制要做的事情就是要衡量中间结点的传输能力,要衡量中间路径上有多少个结点,以及每个结点当前的情况。
那么这里是通过什么来衡量出来的呢?
其实是“实验”,就是通过实验的方式来找到一个合适的发送速率。开始的时候先按照一个小的速率来进行发送,如果发现没有出现丢包的现象,就可以提高一下发送的速率了,如果出现丢包的情况,则立即再把速率调小。也就是让其维持着一个动态平衡的状态。
具体的过程如下所示:
延时应答就是为了提高传输效率,TCP可靠性的核心就是确认应答机制,ACK是要发,但也不是立即就发,而是稍微等一会在发送,发送方如果不停的发送数据,此时接收方接收到数据之后应用程序也在不停的消耗缓冲区里面的资源。此时立即返回一个ACK,此时的ACK是带有一个窗口大小N的,但是如果是稍等一会再发送ACK,此时ACK的窗口大小大概率会比N要大一些。因为在等待的这一小会里面应用程序从接收缓冲区里会消费掉一批数据了,那么就可以让下一次传过来的数据就再多一点了。
延时应答的效果就是通过这个延时让接收方应用程序乘机多消费一点,此时反馈的窗口大小就会更大一丢丢,此时发送方发送速率也就可能会更快一点。
捎带应答他是基于延时应答的一个机制,在客户端中有很多种通信模型:
如下图所示:
如上所示:ACK和SYN的时机本来是不同的,但是由于延时应答的存在,此时ACK就可能会等一会在发送回去,所以就很有可能和SYN合并成一个数据报一起发送回去了。此时合并成一个数据报要比两个数据报效率要更高一些。所以这也就是之前我们将的四次挥手可能会变成三次挥手了,这就是捎带应答起到的效果。
在面向字节流里面有一个比较严重的问题就是粘包问题,那么什么是粘包问题呢?
那么此时站在B主机的角度就不知道要从哪里断开了,是aaa和abbbb还是啥,上述中所谓的一句话就相当于是一个应用层数据报,当A给B连续发了多个应用层数据报之后,这些数据就会累积到B的接收缓冲区中,紧紧挨在一起,此时B的应用程序在读取数据的时候,就难以区分从哪到哪是一个完整的应用层数据报了。就会很容易读出半个包。
那么该如何避免粘包问题呢?归根结底就是一句话,明确两个包之间的边界。
在异常关闭中有以下四种情况:
TCP(传输控制协议)和UDP(用户数据报协议)都是传输层的重要协议,它们都是用来将数据从源主机发送到目标主机的,但它们存在以下几点不同:
每个网络上的设备,都要能分配到一个地址,并要求是唯一的。这个我们可以想象成是我们的身份证号,每个人都有唯一的身份证号用来区别身份。
32位源IP地址本质上是一个32位的整数,通常会把32位的整数转换成点分十进制的表示方式。用三个点分隔,把这个整数分成4个部分,每个部分一个字节,每个部分的取值范围都是0-255。那么32位的整数最多能表示多少个不同的地址呢?他可以表示42亿9千万个。虽然这个数字很大,但是现在全时间有那么多台机器那么多的手机等其他电子产品都要进行分配IP地址,这显然是不够的,那么如何解决上述的问题呢?我们采用了动态分配和NAT机制来进行分配,我们接着往下看。
所谓动态就是让上网的设备才给分配,不上网就不给分配了,此时就可以剩下一大批的IP地址了,但是这显然是一种不靠谱的解决方式,这个机制并没有增加IP的数量,只能在一定程度上缓解,不能彻底解决问题。那么追要想解决问题还是得靠NAT机制。
对于NAT机制来说他是将所有的IP地址分为两大类:一个内网IP,一个是外网IP。
注意:内网设备如果要访问外网设备,就会给他分配一个外网IP。但是外网设备是无法直接访问内网设备的。外网的IP是不可以重复的,但是内网的IP是可以重复的,但是在同一个局域网中是不可以重复的。(就比如一个学校中同一级的班级的班号是不可以重复的,但是每一个学生在同的班级中时,他们的学号就可以重复。但是在同一个班级中学号是不可以重复的。)
NAT背景下的通信:
我们当前使用的大部分IP分配机制都是由动态分配+NAT来解决的。但是我们现在大部分使用的是IPv4他是传统的IP协议,使用的是4个字节,32位来表示IP地址的。现在出来了IPV6,他是更新了一些IP协议,使用的是16个字节,128位来表示IP地址的。它比之前的IP地址多出来了很多很多。但是目前为止还是有很少的在使用IPV6主要是他与IPV4并不兼容,所以大部分都没有进行升级。
从A到B之间,具体路线是怎么走的,在互联网中存在很多冗余的路线,那么A和B之间存在多条路线具体走哪一条,该怎么选择呢?
在网络中,网络环境是十分复杂的,某一个路由器是无法把整个网络环境都记录下来的,路由器只能记录周围的情况,也就是只能知道它的邻居都是谁,这个是由路由器中的一个路由表来进行记录 的,在实际的转发中是渐进式的,类似于问路一样的逐渐接近自己的目标。
IP地址主要分为两个部分,网络号和主机号。
如下图所示:
上述中的198.168.0 就是一个网络号,以及198.168.1也是一个网络号。
此时我们通过路由器就将两个局域网给连接到一起了,此时这两个局域网就称为“相邻”的局域网。这两局域网的网络号是不能重复的。那么对于上述的IP地址中是前三个字节是网络号,但是一定是前三个字节就是网络号吗?那不一定。对于网络号主机号的划分,主要有两种方式一种是IP地址分类(ABCDE),另一种是子网掩码。那么接下来我们就来分别看下它两是怎么进行划分的。
如下图所示:
对于ABCDE这种分法,现在已经几乎不用了。这里小编就不给大家讲解了主要给大家讲解一下子网掩码是分法。
其实我们可以打开我们cmd输入ipconfig就可以查看到自己电脑的子网掩码了。
我们可以看到,这里是255.255.255.0,那就说明IP地址的前24位都是网络号,剩下的8位是主机号,一般像我们家用的网络的子网掩码都是255.255.255.0。
这里先假设子网掩码是255.255.255.0。
数据链路层和物理层对于程序猿来说距离就更远了,在数据链路层中有个协议是以太网。
在上述中的源地址和目的地之就是我们之前给大家交代的mac地址。
CRC是校验和。
IP数据报是用来传输数据的以太网帧。
下面的两个是特殊的以太网帧。
在IP数据报中有一个数字是1500,把这个数据链路层数据帧,最大载荷长度称为MTU。如果承载的数据长度超过MTU,就会在IP层进行分包,是每个分出来的结果都能在MTU之内。
在IP中有一个工作就是来完成这个分包/组包的工作的,如下图所示:
好啦,这节小编就给大家分享到这里啦,这节的内容有点多,大家有啥不会的可以在评论区留言给小编,希望这节对大家了解网络有一定帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)