应用层
应用层是负责应用程序之间沟通的一层。由于不同的网络应用的应用进程之间,有着不同的通信规则,因此自然就需要应用层协议来解决这些问题,这就构成了应用层的主要内容即:精确定义这些通信规则。
应用层有不少应用广泛的协议,像域名系统(DNS)、文件传输协议(FIP)、网络远程访问协议(Telent)等,(具体的协议规则这里不做介绍)除此之外,在日常程序员的工作中使用同样频繁的还有自定义应用层协议;
自定义应用层协议
什么是自定义应用层协议
所谓自定义,即程序的开发者自定义。自定义,包含着一个根据需要从无到有的过程。协议,则代表了某种约定。因此,自定义协议就可以简单理解为由程序的开发者根据程序开发的需要去约定客户端和服务器传输数据的格式;
自定义方式
在约定之前,首先要明确交互过程中传递的信息有哪些。以网上购物为例,用户作为请求的发出方,就需要明确用户的地址,电话号码等信息;而商家则是作为请求的接收方,需要明确商家的一些具体情况,像商品类型,商品销量、商品价格、接单时间等;
根据用户需求明确了交互中涉及到的信息之后,就需要根据实际情况来确定这些信息的组织格式,自此,即真正开始了应用层协议的自定义。
实际需求下,信息的组织格式是有多种方式的:
-
使用简单的分隔符来区分不同部分的信息;
仍然使用商品上网购物的例子,如上图,[;]就是用来区分不同信息的简单分隔符; -
使用固定长度确定不同信息;
使用固定长度来表示不同信息,也根据长度来区分不同信息; -
融合方式一和方式二,一部分字段信息使用分隔符来区分,一部分字段使用固定长度来区分;
-
使用xml格式来约定数据;
xml格式是一种标签结构的用来展示数据的格式,它包含了开始标签和结束标签,标签一般都是成对出现的;
- 使用json格式组织数据;
相比xml,json的使用更加广泛,它是使用键值对的方式来组织数据,每个键值对之间使用逗号进行分割,每个键值对的键和值之间使用冒号进行分割;
json格式的键必须是字符串形式;
- 二进制数据组织格式,protobuffer,thrift;
这种数据组织格式较为复杂,尽管它的效率相比json或xml要更高,且占用的带宽也要更低,但它的可读性却不如前者,在具体使用中,可以根据实际情况进行选择。
运输层
运输层概述
运输层是整个网络体系结构中的关键层次之一,为应用层提供通信服务。其实,对于通信而言,如果是主机对主机之间的通信,网络层即可实现。可是更多的情况下,是端口与端口之间的通信,像主机A的应用程序1与主机B的应用程序2通信,如果在这种情况下,仅仅依靠网络层就无法很好的实现,这时运输层就在这样的通信中起到了关键作用。
运输层特点
一般而言,运输层有2个特点,即复用(multiplexing)和分用(demultiplexing);
复用:即发送方不同的应用进程都可以使用同一个运输层协议传送数据;
分用:接收方的运输层可以把传送来的数据正确交付指定的应用进程;
运输层协议
TCP/IP运输层有2个主要协议,即用户数据报协议UDP和传输控制协议TCP;
UDP协议
UDP协议,即用户数据报协议。UDP数据报传送实际是一种不可靠的传输,因为UDP在传送数据之前不会有建立连接的操作,同时在主机B的运输层收到报文以后也不需要对发送端给出任何确认。但尽管UDP是一种不可靠的传输,也不可避免在一些情况下是有效且便利的。
UDP的特点
-
UDP是无连接的
发送之前不需要建立连接; -
UDP是不可靠传输
其不可靠也是由于其是无连接的; -
UDP是面向数据报的
UDP不会对应用层交付的报文做任何处理,只会原样发送,一次发送一个报文,同时接收端的UDP也是一次交付一个报文; -
UDP传送报文的长度受限
过长的报文在被交付到IP层后可能会被分片,过短的报文被交付会使IP数据报的首部长度过长,都会较低IP层的效率; -
UDP支持一对一、一对多、多对一、多对多的交互通信
UDP首部格式
UDP用户数据报的组成包括了2个字段,即首部字段和数据字段;
首部字段又包含了4个字段,8个字节,每个字段的长度为2个字节;
4个字段分别为:
源端口号:数据发送端的端口号;
目的端口号:数据接收端的端口号;
长度:UDP用户数据报的长度;
校验和:用于检测UDP传输过程中是否出错;
校验规则
UDP校验和是用来校验UDP传输过程是否正确的主要指标。由于在数据通过网络传输的过程中,有可能会受到许多元素的影响。为了避免错误的数据在未知的情况下被传输,规定在发送数据时,将其校验和和数据一起传输。在计算校验和时,是在UDP用户数据报之前增加了12个字节的伪首部。这个伪首部是临时增加在数据报首部的,而不属于数据报真正的首部,也不会被作为向下传递的一部分。
UDP使用的校验和算法,是一种循环冗余校验和(CRC)的方法,具体计算方法这里不做介绍。
TCP协议
TCP协议即传输控制协议。
TCP的特点
-
有连接
TCP在发送数据之前首先需要建立连接; -
可靠传输;
TCP的可靠传输是TCP的核心特点,所谓可靠传输并非是指一旦发送一定接收成功,而是,当数据发送成功后,对方是否接收成功,对于发送方来说是清晰的。通过TCP传输的数据,无差错、不丢失、不重复、按序到达; -
面向字节流传输;
即在发送数据时对数据进行编号是依照字节来编;
TCP协议段格式
TCP协议段是由20个字节的固定首部加数据组成的:
源端口号:数据来源;
目的端口号:数据去处;
序列号:数据编号后得到的序列号;
确认序号:接收到数据后的应答;
首部长度:(4位)表示TCP头部长度;
标志位:URG->紧急指针是否有效;ACK->确认号是否有效;PSH->提示接收端从缓冲区读取数据;PST->对方要求重新建立连接;SYN->请求建立连接,同步报文段;FIN->结束报文段;
TCP的性质
TCP可靠传输的保证,最主要的一点实际就是:确认应答。
确认序号
确认应答首先依靠确认序号来实现,即首先对需要发送的数据(普通报文)进行编号。假设发送的数据编号情况是1—500,则确认序号为501。可以理解为,发送端将编好号的数据发送给接收端后,由接收端给发送端发送一个应答报文,即确认序号,通过确认序号就可以确定当前接收端是对哪个普通报文做出了应答。也就代表接收端已经接收到了该报文。
超时重传
TCP数据的可靠性传输是依靠于应答报文的接收来确定的,而如果发送方发送数据之后等待一定时间但未收到接收方的应答报文,大概率就可以判定为数据传输失败,于是触发重传。
使用超时重传的方式在很大程度上就可以避免数据传输失败的问题,但伴随着超时重传同样也带来了接收端难免会收到一些重复数据的问题;因此,接收方就需要对收到的数据进行去重,也就是根据之前数据的编号进行排查,如若发现收到了一份与之前相同的数据就自动丢弃,依次来保证最终在应用层读到的数据是不重复的。
当然,初始传输的数据可能会丢失,如若处在同样的网络环境中,重传的数据同样也有可能会丢失。而TCP为了保证较高性能的通信,就会不断动态地来计算最大等待时间。像一般情况下操作系统都是以500ms一个单位为基础等待时间,假如在重发之后一个500ms任未得到应答,下次重传就会在2个500ms之后。依次类推~~~
当然,若是多次重传仍然得不到回应,就会强制关闭连接,不再进行传输。
连接管理
TCP作为一种有连接的可靠传输,与它的连接管理机制是分不开的;而所谓连接管理就是TCP经过三次握手建立连接,四次挥手断开连接。
三次握手
TCP通过“三次握手”建立连接,连接的建立一定是由客户端首先主动发起的;
三次握手的主要过程和原理如图,即首先由客户端向服务器发送一个请求尝试建立连接(第一次握手),服务器收到该请求之后向客户端做出应答同时建立与客户端的连接(第二次握手),最后再由客户端对服务器的请求做出应答,至此连接建立成功(第三次握手)~
三次握手是保证数据正常传输的重要前提,只有在通信之前就确定通信链路的畅通,即验证通信双方的发送能力和接收能力,才可以更大程度的成功传输数据。同时在这样一个过程中,客户端与服务器双方也会进行一些重要参数的协商,也是通信中不可避免的一个环节~
四次挥手
四次挥手实际就是通信双方通知断开连接的过程,与三次挥手不同,四次挥手既可以由客户端一方发起,也可以由服务器方发起~
四次挥手的原理如图,任意一方首先发送一个断开连接的请求,对方做出回应之后再发送一个断开连接的请求,待对方最初应答之后,连接断开~
TCP的状态
TCP的状态实际有很多种,这里主要介绍下面几种:
-
LISTEN
一般表示服务器的状态,表示服务器已经启动完毕~ -
ESTABLISHED
表示通信双方连接建立成功,可以进行通信~ -
CLOSE_WAIT
待断开连接的状态,对方发送了断开连接的请求自己也做出了应答,待自己发送断开连接的请求时就是该状态;在Socket编程中,调用close()方法表示断开连接; -
TIME_WAIT
主动发送断开请求的一方的状态,主动方在收到对方断开连接请求同时做出应答之后就处于该状态;该状态持续一段时间后,连接彻底断开~
滑动窗口
以上三种机制确实是保证了TCP传输的可靠性,但从某个角度来说,反复保证可靠传输的操作也不可避免地降低了TCP通信的效率,因此为了尽可能地提高其传输效率,就产生了滑动窗口的机制。
最基本的TCP通信是主机A发送一条数据,待主机B返回应答报文后,主机A再继续发送下一条数据,而添加了滑动窗口机制的TCP特性则是一次发送一批数据,这一批数据有可能包含了多条单个的数据,待对方返回了第一条数据的应答报文之后,主机A就继续发送下一批数据,这就是滑动窗口的基本工作原理。
至于这里一批数据包含了多少条数据,就在于这个窗口的大小,窗口大小越大,一次发送的数据就越多,相应其发送速率也就越高。
与普通的TCP传输相同,增加了滑动窗口机制的TCP通信同样有可能会出现丢包的问题,那么它们对于丢包的处理又会有什么不同呢?
第一种情况是传输的数据本身丢了:
发送方通过接收到的应答报文来判断是否出现了丢包,假设发送方一次发送了1-1000、 1001-2000、 2001-3000三条数据,同时收到的多条应答报文都是1001,就可以断定后面的2条数据发生了丢包,此时发送方就会重新发送后面的2条数据,而不会重复发送第一条数据。因此,对于数据本身丢包,原则就是丢哪条,重发哪条,对于成功传输的数据,则不会重复发送。
第二种情况是应答报文丢了:
一般情况下,无论网络环境有多么复杂,丢包始终都是一个小概率事件,因此假设数据的发送情况与上面一致,但接收到的应答报文却只有2001和3001,对于发送方来说,是可以认为1-1000的数据也是顺利到达了的,即对于应答报文涵盖的信息,后一个是会包含上一个的。
我们说滑动窗口的机制是提高TCP的通信效率,但这只是针对没有滑动窗口时的普通的TCP通信,如果是与不保证可靠性的UDP相比,自然是不及UDP的效率的。因此,与其将滑动窗口机制看做是提高效率的方式,不如认为是对低效率的补救。
流量控制
流量控制实际就是对滑动窗口进行限制的一种机制,因为对于滑动窗口而言,窗口越大,数据的发送效率就越大。但如若这个效率过大,又会带来丢包等一系列的问题,因此对其效率进行控制就是必要的。
由于接收端接收到数据之后,是将数据暂时存储在缓冲区,等待接收端的应用程序来读取数据,因此如果发送方发送数据过多过快,就会出现接收端的缓冲区被占满的情况,若是在这种情况下,发送方仍然不停地发送数据,丢包现象的产生也就是必然的了。而流量控制就是TCP根据接收端的处理能力,来制约发送端的发送速度。
如何制约呢?
前面我们再介绍TCP协议段格式时,就包含了一个代表窗口大小的字段,这里的制约方式实际就是接收端将自己剩余的缓冲区的大小存取该字段中,再通过ACK应答报文来告知发送端,发送端就可以根据这个窗口大小来调整自己的发送效率,避免接收端缓冲区满仓。
关于流量控制机制需要注意这样几个点:
窗口大小的字段越大,就说明网络的吞吐量越高;
当窗口大小为0时,发送方就不会再发送数据;但在一段时间后,发送方一般会尝试发送一个探测包,来查验接收端此时的数据处理能力;
实际的窗口大小是窗口字段的值左移M位,M代表窗口扩大因子;
拥塞控制
如果说,前面的流量控制是站在接收方的角度控制发送速率,那么拥塞控制就是站在整个发送过程的角度来调整发送速率。
一般为了数据传输效率和可靠性的保证,TCP是采用慢启动的机制的,即在网络状况未知的情况下,先发少量的数据来探路,再根据实际情况来确定实际的传输速率。
可以理解为整个发送过程就是这样的:初始发送时按照较小的窗口大小来发送,如果没有出现丢包的问题,就判定网络环境良好,可以尝试发大发送窗口的大小,在不断发大的过程中,如若出现丢包的情况,就立即减小发送的窗口,利用这样反复试探的操作,来寻求一个动态平衡的局面;
在TCP中,具体的操作是这样的:
此处可以引入一个拥塞窗口的概念;假定第一次发送时,拥塞窗口的初始值为1,每次发送方收到一个ACK应答,拥塞窗口值加1,具体的发送速率就由拥塞窗口和之前流量控制中的窗口的较小值来决定;
一般TCP拥塞窗口的初始增长速度是非常快的,基本是指数级别的增长,到达一定的阀值后,就变为线性增长;
延迟应答
延时应答同样是一个用来提高TCP通信效率的机制,它更像是对前面流量控制的一种缓解。顾名思义,延时应答就是接收端在接收到数据以后等待一定时间再像发送端返回应答,而在这样一个等待的时间里,接收端的接收缓冲区仍在不停地被应用程序读取,缓冲区的剩余容量也在不断增加,等到真正返回ACK报文时,可以返回的窗口大小也就会更大;
但是对于延时应答,也是有一定限制的:
数量限制:每隔N个包就应答一次;因为后面的应答报文时可以涵盖前面的数据接收情况的,即2001的应答报文表示收到了1-2000的所有数据;
时间限制:超过最大延迟时间就应答一次;这一点对于不同的操作系统有不同的时间限制,超过该时间限制则应答一次;
捎带应答
捎带应答同样是一种提高传输效率的机制,是基于延时应答而实现的;因为正常情况下,ACK报文是接收端接收到请求之后,由内核立即返回的,而具体的响应数据则是由代码实现来控制的,但是如果基于延时应答的机制,ACK报文延时发送,在时间上就可能与响应数据重合,也就达到了捎带的目的。
TCP的通信整体而言是比较复杂的,因为它在保证可靠性的同时又在尽可能的提高性能。在其整个机制系统中,校验和、序列号、确认应答、超时重传、连接管理都是在保证其可靠性,而滑动窗口、延时应答、捎带应答则是在提高其传输性能。
粘包问题
TCP是基于字节流的传输层通信协议。这里的基于字节流实际是指在读取接收端缓冲区的数据时以“字节流”的方式来读取,但是面向字节流的方式势必会带来一个问题,即粘包问题;
由于“流”数据是没有明确的开始和结尾边界的,对于同一进入到接收端缓冲区的众多数据而言,更是难以区分这些数据来自何处,结束于何处,因此在进行数据的读取时,就有可能会出现在一条消息中读取到了另一条消息的部分数据,这就是粘包问题。
如何解决粘包问题呢?
常见的解决办法主要有2种:
- 约定长度: 发送方和接收方固定发送数据的大小,明确边界;
- 使用分隔符,类似于前面的自定义应用层协议;
异常情况处理
异常情况主要就是发送方与接收方以非正常四次挥手的方式断开连接,主要有下面几种情况:
-
主机关机
如果是按照正常程序逐步关机,会首先释放进程,然后释放文件描述表上对应的文件资源,然后触发结束报文段,开启四次挥手的流程,若流程顺利结束,无影响继续关机,若流程未完成,就重新发送FIN结束报文段,得不到回应就自行断开,放弃~ -
程序崩溃,进程终止;
与上面流程基本一致~ -
机器掉电/网线断开
极端情况下,当来不及进行四次挥手操作时,对于接收方突发异常而言,对方发送数据得不到ACK,就尝试重传,如此多次之后仍无法成功就放弃操作;对于发送方突发异常而言,接收方无法得知具体情况(是暂未发送数据还是发送方故障了),在长时间等待不到数据的情况下,就会通过发送心跳包的方式周期性地去判定对方是否仍然存活,如果可以得到回应,证明只是暂未发送数据,若得不到回应,表示发送方故障;文章来源:https://www.toymoban.com/news/detail-404925.html
至此,关于网络五层模型中最重要的应用层与传输层重点协议就介绍完毕啦,over~~文章来源地址https://www.toymoban.com/news/detail-404925.html
到了这里,关于应用层与传输层~的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!