网络分层结构并考虑最简单的情况:两台主机之间的通信。这时只需要一根网线连接两者,规定彼此的硬件接口,如USB,电压10v,频率2.4GHz等。这一层是物理层,这些规定就是物理层协议。当然,我们并不满足于只连接两台电脑,所以我们可以用一个交换机连接多台电脑,如下图:这样连接的网络称为局域网,也可以称为以太网(以太网是局域网的一种。)。在这个网络中,我们需要识别每台机器,以便我们可以指定与哪台机器进行通信。这个标识就是硬件地址MAC。硬件地址随机机的产生是确定的,永久唯一的。在局域网中,当我们需要与另一台机器通信时,只需要知道它的硬件地址,交换机就会将我们的消息发送给相应的机器。这里我们可以不管底层网线接口如何发送,把物理层分离出来,在它上面新建一层,就是数据链路层。我们仍然不满足于局域网的规模,我们需要将所有的局域网都连接起来。这时候,我们就需要使用路由器来连接两个局域网:但是如果我们仍然使用硬件地址作为通信对象的唯一标识,那么当网络规模变大的时候,记住是不现实的所有机器的硬件地址;同时,一个网络对象可能会频繁更换设备,这时硬件地址表的维护就比较复杂了。这里用一个新的地址来标记一个网络对象:IP地址。通过一个简单的发送信件的例子来理解IP地址。我住在北京,我的朋友A住在上海。我想给朋友A写一封信:写完信后,我会在信上写上朋友A的地址,然后投到北京邮局(在信息IP地址中添加一个目标,发送到路由器)邮局帮我把信送到上海当地的邮局(信息会路由到目标IP局域网的路由器)上海当地的路由器帮我把信送到朋友A(局域网内通信)所以,这里的IP地址是一个网络访问地址(朋友A的地址),我只需要知道目标IP地址,路由器就可以给我带来消息了。在局域网中,可以动态维护MAC地址和IP地址的映射关系,根据目的IP地址找到本机的MAC地址并发送。这样我们就不需要去管理底层如何选择机器了。我们只需要知道IP地址即可与我们的目标进行通信。这一层是网络层。网络层的核心作用是提供主机之间的逻辑通信。这样,网络中的所有主机在逻辑上都是相连的,上层只需要提供目标IP地址和数据,网络层就可以将报文发送给相应的主机。一个主机有多个进程,进程之间进行不同的网络通信,比如和女朋友微信聊天,和朋友打开黑匣子。我的手机同时与两台不同的机器通信。那么当我的手机接收到数据时,如何区分是微信数据还是王者数据呢?那么就需要在网络层之上再增加一层:传输层:传输层通过socket进一步拆分网络信息,不同的应用进程可以独立进行网络请求,互不干扰。这就是传输层最本质的特性:提供进程间的逻辑通信。这里的进程可以在主机之间,也可以是同一个主机,所以在android中,socket通信也是进程通信的一种方式。既然不同机器上的应用进程可以独立通信,那么我们就可以在计算机网络上开发各种应用程序了:比如用于网页的http,用于文件传输的ftp等等。这一层称为应用层。应用层可以进一步拆分为表现层和会话层,但它们的本质特征没有改变:完成特定的业务需求。与下面四层相比,它们不是必须的,可以归于应用层。最后对网络规划层做一个总结:最底层的物理层负责两台机器之间通过硬件直接通信;数据链路层在局域网中使用硬件地址进行寻址,实现局域网通信;网络层使用抽象IP地址实现主机间的逻辑通信;传输层在网络层的基础上,对数据进行拆分,实现应用进程独立的网络通信;应用层在传输层的基础上,根据具体需求开发各种功能。这里要注意,分层不是物理分层,而是逻辑分层。通过对底层逻辑的封装,上层的开发可以直接依赖底层功能而不用关注具体的实现,简化了开发。这种分层的思想,即责任链设计模式,通过层层封装将不同的职责分离,使得开发和维护更加方便。TCP是面向字节流的。TCP不会直接给应用层传来的数据加上头部,然后发送给目标。相反,它将数据视为字节流,用序列号标记它们,然后分段发送。这就是TCP面向字节流的特性:TCP会以流的形式从应用层读取数据,并存储在自己的发送缓冲区中,同时给这些字节打上序号。TCP将从发送缓冲区中选择适当的数量。字节组成一个TCP消息,通过网络层发送到目标。目标将读取字节并将它们存储在其接收缓冲区中,并在适当的时间将它们传递给应用层。大数据占用太多内存。缺点是无法知道这些字节的含义。例如,应用层发送一个音频文件和一个文本文件。对于TCP来说,就是一连串的字节流,根本没有任何意义,会导致粘连和解包的问题,??后面会讲到。可靠传输的原理前面说过,TCP是一种可靠的传输协议,就是如果把一份数据交给他,他一定能够完整无误地发送到目标地址,除非网络炸毁。它实现的网络模型如下:对于应用层,是可靠传输的底层支撑服务;而传输层底层采用网络层的不可靠传输。虽然可以在网络层甚至数据链路层使用协议来保证数据传输的可靠性,但是网络设计会更加复杂,效率也会相应降低。将数据传输的可靠性保证放在传输层上会更合适。可靠传输原理的要点总结如下:滑动窗口、超时重传、累积确认、选择确认、连续ARQ。停止等待协议要实现可靠传输,最简单的方法是:我给你发一个数据包,你回复我,我继续发送下一个数据包。传输模型如下:这种“一来一去”的保证可靠传输的方法就是停止等待协议(stop-and-wait)。不知道我还记不记得前面的TCP头中有一个ack字段。当设置为1时,表示此消息是确认消息。再考虑另一种情况:丢包。网络环境不可靠,导致每次发送的数据包都丢失。如果机器A发送一个数据包丢失了,那么机器B永远收不到数据,机器A会一直等待。这个问题的解决方法是:超时重传。当机器A发送一个数据包时,它开始计数。如果时间到了,没有收到确认回复,可以认为发生了丢包,重新发送,即重传。但是重传会带来另外一个问题:如果原来的数据包没有丢失,而是长时间停留在网络中,此时机器B会收到两个数据包,那么机器B如何区分这两个数据包呢?这些包属于相同的数据还是不同的数据?这就需要用到前面提到的方法:对数据字节进行编号。这样,接收方就可以根据数据的字节数判断该数据是下一个数据还是重传数据。TCP头中有两个字段:序号和确认号,分别代表发送方数据的第一个字节的序号和接收方期望的下一条数据的第一个字节的序号。连续ARQ协议停等待协议可以满足可靠传输,但它有一个致命的缺点:效率太低。发送方发送一个数据包后等待,在此期间不做任何事情,浪费资源。解决方法是:不断发送数据包。模型如下:与stopwaiting最大的区别是它会不断发送,接收者在不断收到数据后会一一确认并回复。这大大提高了效率。但同样,它带来了一些额外的问题:发送方是否可以无限发送,直到发送完缓冲区中的所有数据?不能。因为你需要考虑接收方的缓冲区和读取数据的能力。如果发送速度太快,接收方无法接受,只会频繁重传,浪费网络资源。因此,发送方发送的数据范围需要考虑接收方的缓存情况。这就是TCP流量控制。解决方案是:滑动窗口。基本模型如下:发送方需要根据接收方的缓冲区大小设置自己的可发送窗口大小,窗口内的数据可以发送,窗口外的数据不能发送。当窗口中的数据收到确认回复后,整个窗口会向前移动,直到发送完所有数据。TCP的头部有一个窗口大小字段,表示接收方剩余的缓冲区大小,以便发送方可以自行调整发送窗口的大小。通过滑动窗口,可以实现TCP的流量控制,以免发送速度过快,导致数据丢失过多。连续ARQ带来的第二个问题是网络中充斥着与发送数据包数据量相同的确认回复消息,因为每个发送的数据包都必须有一个确认回复。提高网络效率的方法是:累积确认。接收方不需要一一回复,而是在累积一定数量的数据包后,告诉发送方这个数据包之前的所有数据都已经收到了。比如收到1234,接收方只需要告诉发送方我收到了4,那么发送方就知道1234已经收到了。第三个问题是:丢包怎么处理。在stop-wait协议中很简单,超时重传就解决了。但是,在连续ARQ中就不一样了。例如:接收方收到123567,6个字节,第4个字节丢失。按照累积确认的思路,只能发送3次确认回复,必须丢弃567,因为发送方会重传。这就是GBN(go-back-n)的思想。但是我们会发现我们只需要重传4次,不算浪费资源,于是就有了:选择确认SACK。在TCP报文的选项字段中,可以设置接收到的报文段,每个报文段需要确定两个边界。这样发送方只能根据这个选项字段重传丢失的数据。可靠传输总结至此,TCP的可靠传输原理介绍的差不多了。最后总结一下:通过连续ARQ协议和send-acknowledgementreply方式保证每个数据包到达接收端通过给字节编号来标记每条数据是属于重传还是新数据重传通过timeout来解决问题的方式网络中的数据丢包是通过滑动窗口实现流量控制,通过累积确认+选择确认的方式来提高确认回复和重传的效率。当然,这只是可靠传输的冰山一角。如果有兴趣,可以深入研究。来源:https://www.toutiao.com/i6954...
