应用层:和应用程序密切相关,HTTP协议就是一种常见的应用层协议。程序猿也可以自己约定一些协议。
负责数据能够从发送端传输接收端。(传输层和网络层是操作系统内核实现好的.普通程序猿不能修改)
核心功能:完成“端对端”的数据传输。
传输层协议有很多,最常用的有两个:UDP 和 TCP
面试高频考点:TCP和UDP的区别?
UDP传输的过程类似于寄信.
TCP全称为 “传输控制协议(Transmission Control Protocol”), 要对数据的传输进行一个详细的控制。
特点: 有连接、可靠、面向字节流。
TCP将每个字节的数据都进行了编号, 即为序列号,每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发。
主机A发送数据给B之后, 可能因为网络拥堵等原因,数据无法到达主机B;如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发;因此主机B会收到很多重复数据,TCP协议需要能够识别出重复的包, 并且把重复的丢弃掉。这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。
在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。
三次握手:
三次握手的本质,其实是确认通信双方,发送能力和接受能力都正常。具体过程如下图:
当客户端和服务端建立连接的时候,客户端会向服务端发送一包连接请求数据(SYN),询问能否建立连接;服务端同意连接后,会给客户端发送SYN+ ACK (确认报文段)包;客户端收到之后再回复一个ACK 包,这样,连接建立。
四次挥手:
处于连接状态的客户端和服务端都可以发送关闭请求。
TCP 协议的常见状态:
TIME_WAIT存在的意义:是为了防止最后一个ACK丢包做准备的。
当进行最后一个ACK发送完之后,并不会立刻就销毁连接,而是以TIME WAIT的状态,等待一定的时间,一定时间之后,发现对方没有重传FIN,就视为ACK没丢包,于是就真正断开连接;一定时间之后,发现对方重传了FIN,说明最后一个ACK丢了,就重传ACK,再次进行等待。
TIME WAIT等待的时间,2 MSL,MSL表示网络中,两个主机之间传输数据的最大时间间隔。
建立连接,一定是客户端主动发起连接请求;
断开连接,客户端和服务器都可以做;
前面对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段。这样做有一个比较大的缺点:就是性能较差。
可以让发送方批量的发送一组数据,统一等待ACK。这一组数据能发多少,这个数据量,称为“窗口大小”。
窗口范围内的数据就是已经发出去的数据,同时也是要等待ACK的数据。随着对方的ACK的到达,要等待的数据也就随之发送变化。同时也会发送新的数据出去.看起来就好像“窗口滑了一个格子一样”。
操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据, 才能从缓冲区删掉。
当前有了滑动窗口之后,看起来可靠性也有,效率也有。但是滑动窗口的窗口大小,到底要多少合适??窗口越大,传输效率就越高,但是内存消耗就更大;窗口越小,传输的效率就越低,内存的消耗也就小了。不仅仅是内存,还有一些东西会影响到“窗口大小”,典型的——接收方的处理速率。
此时就需要根据接收方的处理能力,限制一下发送方的窗口大小,这种机制就被称为:流量控制。
接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送, 就会造成丢包,继而引起丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。
发送方先有一个初始的窗口大小,发送数据过去之后,对方返回一个ACK,ACK中除了有确认序号之外,还有一个数据,表示“接收方缓冲区的剩余空间大小”。在ACK报文中,告诉发送方,接收方的接受缓冲区的空闲空间,根据这个大小,发送方来决定接下来按照多大的窗口来传输速度。
所以:在TCP协议格式中,发送方会根据16位窗口大小来确定发送方的窗口大小。
但在真实的网络环境中,发送方和接收方不是通过一根网线直接连接的,而是经理很复杂的网络结构,因此发送方不仅要考虑接收方的处理能力,还要考虑一些中间节点的处理能力。
滑动窗口的大小由拥塞控制+流量控制一起决定的。
由于网络环境比较复杂,也不知道中间经历了多少节点。发送方,采取一个动态变化的过程,来试探出当前的窗口大小多少合适。发送方会在初始情况下,设置一个比较小的“窗口大小”(慢开始)发一下数据试试,如果没丢包,说明网络畅通,就开始尝试一个更大的窗口大小,如果还没丢包,网络还是畅通,继续尝试一个更大的窗口大小。一直到出现丢包了,缩小窗口大小,循环上述过程。
滑动窗口的实际大小,就是拥塞窗口和流量控制窗口的较小值。
如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。当主机B收到A的数据之后并不是立刻返回ACK而是等待一会(500ms)再返回ACK,ACK携带的窗口大小,就可能会更大。
最常见的服务器的通信模式,“一问一答”。应用程序返回响应的时候,顺带把上个ACK数据也一起携带过去,减少了传输的数据包的个数,减低了通信成本,提高了效率。
当主机 A 和主机 B 建立连接以后,会在各自的内核里维护一对缓冲区——发送缓冲区和接收缓冲区。
主机 A给主机 B 发送一个hello,主机A先调用系统提供的send方法,将这个hello字符串放到发送缓冲区里,接下来缓冲区的数据何时真的通过网络传输出去,由内核决定;
主机 A 把 hello真的发送出去后,数据通过网络到达主机 B 的接收缓冲区,主机B通过使用系统提供的recv方法从接收缓冲区中读取这个数据,可以一次读一个字节,也可以一次多读或者一次读完。
因此会出现问题。如果发送方给接收方一下发送了多组数据,接收方从缓冲区读数据的时候,可能会出现“歧义”,如果是形如下面的情况:
发送方发了多条数据过来,接收方所有的数据都在接收缓冲区中混成一片了,这个时候就难以区分,从哪到哪是一个完整的应用层数据了,就产生了“粘包问题”。
粘包问题:
注意:
如何解决粘包问题?
设计应用层协议的时候,能够显式的区分出来数据包的边界。
保证可靠性:
保证效率:
可能出现问题的代码:
网络层主要负责两件事:
IP协议当前主要是两个版本,IPv4,IPv6。谈到IP协议,主要还是指IPv4(当前网络里主要的设备还是通过IPv4来通信)。
IP地址分为两个部分, 网络号和主机号:
同一个局域网中,各个设备的网络号相同,主机号不同;两个相邻的局域网,网络号不能相同。
具体的划分方式:
ABCDE五类 IP 地址
该方式已经消失在历史的长河中,仅存于教科书中了。
子网掩码也是一个32位的整数,特点就是,从二进制的角度看,前半部分都是1,后半部分都是0。拿着子网掩码和IP地址进行按位与操作,得到的结果就是网络号,剩下的部分就是主机号。
在复杂的网络结构中, 找出一条通往终点的路线。相当于问路。
只关注两个相邻节点之间的传输情况。
插网线的有线网,这个就是“以太网”;平时用的网线,都叫做“以太网线”。
关于网络传输的数据,涉及到几个不同的概念~~
mac地址,也叫做“物理地址”,是和主机的网卡设备绑定的,只要主机出厂,mac地址就被写死了。每个设备的mac地址都是唯一的,不会冲突(就算有少量的冲突,其实问题不大,只要局域网里不冲突就行)。
已经有IP地址了,为啥还有mac地址呢?历史上,网络层协议和数据链路层协议,是各自独立发明出来的,实际使用的时候,又给这两种地址,找到了不同的定。
IP地址立足于全局,进行网络路线规划;mac地址立足于局部,只关注相邻节点的通信。
DNS是一整套从域名映射到IP的系统。即域名解析系统。