网络分层结构
计算机的网络体系分为三种,OSI网络分层结构,TCP/IP 五层模型,TCP/IP四层模型。
TCP/IP五层模型:
- 应用层:为应用程序提供交互服务,在应用层中有较多的协议,较为出名的是:HTTP协议、域名系统DNS、SMTP协议
- 传输层:负责向两台主机之间的通信提供数据传输服务,常见的协议是:TCP协议、UDP协议
- 网络层:选择合适的路由和交换结点,确保数据的及时传输,常见的协议是:IP协议
- 数据链路层:在两个相邻的节点之间进行传输数据时,数据链路层会把上一层交付的IP数据报组装成帧,然后在两个相邻的节点的链路上传送帧
- 物理层:实现一个透明的比特流传输,尽可能的避免传输介质和物理设备的差异。
OSI七层网络分层结构:
- 应用层:实现网络服务和最终用户的一个接口,常见的协议是:HTTP协议、DNS协议、SMTP协议
- 表示层:表示 数据的安全、压缩、表示,确保一个系统的应用层发送的数据能够被另一个系统的应用层准确的接收
- 会话层:建立、终止、管理会话,对应主机的进程,指代本地主机和远程主机之间的会话
- 传输层:定义数据传输的端口号协议,以及流控和差错校验,常见的协议是:TCP协议和UDP协议
- 网络层:进行逻辑选址和实现不同网络之间的路劲选择,常见的协议是IP协议
- 数据链路层:在物理层提供的透明的比特流传输的服务上,在两个相邻的节点上建立数据链路
- 物理层:进行物理的建立、维护、断开物理的链接
TCP协议的特点:
- TCP协议是面向链接的
- TCP协议是提供可靠交付服务的
- TCP协议是全双工通信的
- TCP是点对点的,一条TCP链接上只能由两个端点
- TCP协议是面向字节流的,它会将数据当作一群无结构的字节流
TCP协议和UDP协议的区别:
- TCP协议是面向链接的,即TCP协议在建立之前必须要客户端和服务端之间建立链接,而UDP协议是不需要建立链接的,是无链接协议
- TCP协议是面向字节流的,即TCP协议会将数据当作一群无结构的字节流进行数据的传输,而UDP协议是面向报文的,会将数据当作报文进行传输
- TCP协议是拥有拥塞控制的,拥塞控制是指在网络进入拥塞时,TCP会降低传输数据的效率以此确保数据能够正确的抵达接收方,而UDP并没有拥塞控制,所以UDP并不与会降低发送数据的效率,而也正是如此,UDP更适应与一些网络实时的数据传输工作,例如 实时视频会议 这类实时应用。
- TCP协议是点到点的协议,每一个TCP链接只能有两个端点,而UDP协议是一对多、多对多、多对一、一对一的通信方式。
TCP协议如何确保可靠性:
- 首先, TCP协议的链接和断开是基于三次握手和四次挥手,这确保的TCP链接的建立和断开的可靠性。
- 其次,TCP的可靠性还体验在TCP协议会记录那些数据被发送了、那些数据被接收了、数据是否发送成功、确保了数据包能够按顺序进行发送,保证了数据发送不出错。
- 最后,TCP协议的可靠性还体验在TCP协议的可控制上,TCP协议拥有 拥塞控制、数据包校验、ACK应答、超时重传、失序重传、丢弃重复的数、流量控制、滑动窗口机制等。
TCP的三次握手和四次挥手
三次握手:
首先,我们将发送方称为客户端,接收方称为服务端,在TCP建立握手之前,客户端和服务端的状态都是 close 状态 ,也就是关闭链接状态。
- 第一次握手,客户端 想要和服务端建立TCP 链接,就需要向服务端发送一个建立链接的数据报文段 SYN ,其报文段的标记位是 SYN=1 ,同时产生一个序列号 seq =x 。发送完毕后,客户端会进入SYN-SENT 状态,也就是等待确认状态,而服务端此刻也会变成 listen状态。
- 第二次握手,服务端接收到了客户端发送的SYN报文段,同时在接收的时候会产生一个序列号 seq =y ,一个确认号 ACK -1 ,并向客户端发送一个建立链接的数据报文段和一个确认报文段,SYN=1,seq=y ,ACK=1,同时从listen状态转变成SYN-RCVD状态。
- 第三次握手,当客户端接收到了服务端发送的确认报文段和建立链接报文段后,客户端将会再一次的向服务端发送确认报文段,ACK=1,seq=x+1,ack=y+1,表示已经准备就绪。当发送完报文段的同时,当服务端接收到后,二者就会立马进入ESTBLISHED状态,进入此状态后,二者就此建立了TCP的链接。
为什么要三次握手而不是两次握手?
三次握手和两次握手的区别就在于三次握手的二次确认,三次握手需要由客户端确认了服务端发送的确认报文段后,再次朝服务端发送确认报文段,而两次握手并没有这一次的操作。
如果只有两次握手,那么可能会导致已经失效的链接请求报文段突然的传输到服务器上,产生一系列的问题。
例如:
- 假设客户端是A,服务端是B,那么A为了和B建立TCP链接,于是A朝B发送了一段SYN建立链接的报文段,但是由于网络堵塞的原因,导致B没有接收到这一次的请求,而A因为没有接收到B发送的确认报文段,所以A会再一次的发送建立TCP链接的请求。
- 所以这里的A发送了两次建立TCP链接的请求,第一次没有让B接收到,而第二次让B接收到了。
- 因为B接收到了第二次的请求,二者很快的建立了链接(这里是二次握手的方式进行链接)。
- 建立链接后,二者很快的就进行数据的传输,等数据传输完毕后,二者又很快的结束链接,然后这时,A发送的第一次建立TCP链接的数据报文段抵达了B。
- B误以为这是A又需要和自己建立链接于是很快的就向A发送确认报文段,但是A只需要和B建立一次TCP链接就行了,于是没有理会,而因为没有被A接收的确认报文段,这导致B一直都处在了等待链接的状态。
- 而B一直处在等待链接状态则会转变为浪费资源。
所以如果TCP链接只有两次握手,那么只需要服务段发送确认报文段即可进入TCP链接,而A不回应服务端发送的确认报文段,那么服务端则会导致资源的浪费。
四次挥手:
首先,我们将发送方称为客户端,接收方称为服务端,在TCP断开链接之前,客户端和服务端是出于链接状态的。
不仅如此,因为TCP的全双工通信的,所以这就导致了,客户端和服务端虽说是一条TCP链接,但是有两个传输的管道,分别是客户端朝服务端传输数据的链接,以及服务端朝客户端传输数据的链接。
所以TCP的断开链接,TCP的四次挥手的本质意义就是要分别的断开两条数据链接。
其次TCP在断开链接之前都是处在ESTABLEISHED状态的。
- 第一次挥手,因为客户端没有数据要传输给服务端,所以客户端想要断开服务端的链接,所以客户端会朝服务端发送一个终止链接的报文段,FIN=1,并产生一个初始序列号seq=u,随后客户端会转变到FIN-WAT-1 等待状态。
- 第二次挥手,服务端收到了客户端发送的终止链接报文段后,转变为CLOSE-WAIT 半关闭状态,也就是客户端无法朝服务端发送数据,而服务端依旧可以朝客户端发送数据,其次服务端收到报文段后,会朝客户端发送 确认报文段 ACK=1,并且产生一个初始序列号 seq=v 和一个确认号 ack=u+1,等待客户端收到确认报文段后,会进入FIN-WAIT-2状态。
- 第三次挥手,第三次挥手是由服务端发起的,因为服务端没有数据需要传输到客户端了,所以服务端朝客户端发送终止链接报文段,FIN=1,ACK=1,ack=u+1,seq=w,并且服务端自动转入LAST-ACK 等待确认状态。
- 第四次挥手,当客户端接收到确认报文段后,会再一次朝服务端发送确认报文段,ACK=1,seq=u+1,ack=w+1,并且进入时间等待状态 TIME-WAIT 等到时间2MSL,以及服务端准时收到了报文段后,二者同时进入CLOSE状态,表示断开连接。
第四次挥手为什么要等待2MSL?
- 首先,等待2MSL的原因是 因为客户端朝服务端发送的最后一次确认报文段有可能会因为网络堵塞等原因造成丢失导致服务端没有接收到最后一个确认报文段,而因为TCP的一个特点“超时重传”,如果服务端没有在一定的时间内(这个时间一定是在2MSL范围内的)收到这个报文段,那么服务端则会朝客户端发送一个报文段,让客户端进行重传操作。
- 而如果没有这个2MSL的时间进行等待,那么客户端会直接进入关闭状态,就接收不到服务端发送的重传报文段,而服务端也会因此陷入异常状态,所以这个2MSL时间等待是为了保证客户端能够接收服务端发送的重传报文段,保证二者能够正常的进行关闭。
- 其次,这个2MSL时间就是为了让一些报文段(例如上面描述的因网络堵塞而导致无法传递到服务端的确认报文段) 过期,让这些报文段过期、失效,这样在下一次的链接中就不会因为无关的报文段导致链接出现差错。
TCP的粘包和拆包
概念:
TCP是面向字节流的,所以TCP的底层是不了解上层所需要的数据的具体含义,且TCP会把数据当作一群没有结构的字节流,所以TCP对数据的划分是根据TCP内部的缓冲区进行划分的,这也导致了一个完整的数据包会因为TCP内部缓冲区的原因,被拆分或者和其他的数据包粘贴,这也就是TCP的拆包和粘包。
TCP的粘包和拆包的产生:
粘包:
- 要发送的数据包小于TCP缓冲区的剩余大小,那么TCP会为了方便进行多次的写入数据包,导致多个数据包进行粘粘。
- 或者是接收数据包的上层/应用层因为没有及时的读取TCP发送的数据包,导致这个数据包仍然处在TCP的缓冲区中,而这也导致了粘包
拆包:
- 如果要发送的数据包大于了TCP内部缓冲区的大小,那么这个数据包将会被TCP划分切割,从而导致拆包
- 又或者是发送的数据包的数据远远的超过了MSS(最大数据报文段的长度),那么TCP在传输的过程中会进行拆包操作。
解决方案:
- 将每一个数据包进行固定长度的封装
- 在数据包的末尾增加特殊字符方便之后按照固定长度进行切割
- 将数据包分为两个部分,一个是头部,一个是内容部分,其中头部部分的大小固定,且包含了内容部分的大小声明字段。
TCP滑动窗口机制
TCP利用了滑动窗口的机制来实现流量控制。流量控制是为了控制发送方发送数据的效率,保证接收方能够及时的接收。
TCP链接的双方都会各自维护一个窗口,发送方维护发送窗口,接收方维护接收窗口。同时接收方维护的接收窗口,它的大小取决于应用、系统、硬件的限,而发送方的发送窗口取决于对应的接收方的接收窗口的大小。
接收方的接收窗口可以利用 发送的确认报文段 中的 Window字段来操控发送方的发送窗口大小,以此来控制和影响发送方的发送效率, 倘若接收方将确认报文段中的 window字段设置值为0,那么发送方将不能进行数据的发送。
TCP的拥塞控制
概念:
TCP拥塞控制是建立在TCP的链接基础上,为了防止在发送方和接收方在进行传输数据时遭遇网络波动而导致传输数据丢失而设置的。
慢开始:
- 假设当前的发送窗/拥塞窗口cwnd的数值是1,当cwnd=1时,表示发送方能够连续朝接收方发送1歌数据报文段,且在接收方准时无误的接收到数据报文段后,会连续朝发送方发送1个确认报文段,当发送方接收到接收方连续发送的1个确认报文段后,发送方的拥塞窗口cwnd数值会从1变成2,即cwnd=2。
- 这时,发送方因为cwnd=2的原因,可以连续向接收方发送2个数据报文段,同时接收方能够连续的接收到2个数据报文段后,也会向发送方连续发送2个确认报文段,当发送方接收到连续的2个确认报文段后,发送方的cwnd值就会从2变成4 。
- 这就表示发送方可以连续的朝接收方发送4个数据报文段,同时接收方需要连续接收到4个数据报文段,并连续的发送四个确认报文段给发送方.......
直至cwnd 的数值大小,等于或者大于慢开始门限数值时,慢开始才继而结束。
拥塞避免:
对于拥塞避免,拥塞避免触发的前提是 使用了慢开始算法后,让cwnd数值等于慢开始门限数值后,开始使用。
当cwnd等于慢开始门限数值后,cwnd数值只能在每次接收到接收方连续发送的确认报文段后,进行线性的+1。
例如:
- 设置的慢开始门限数值是16,而拥塞避免从16开始进行使用,当接收方接收到了连续的16个数据报文段后,连续的发送了16个确认报文段交给发送方,而发送方准确无误的接收后,它的cwnd数值并不能向之前一样进行成倍的增长,而是线性的+1增长,也就是cwnd不能等于16*2 =32,而是16+1=17 。
- 所以之后的发展便是:发送方连续发送17个数据报文段,接收方连续的接收到了17个数据报文段后,连续的发送了17个确认报文段,随后发送方接收到了17个确认报文段后,cwnd从17变成了18。
- 而假设当cwnd数值在24的时候遇到了网络拥塞,也就是发送方发送了24个报文段给接收方,但是接收方直接受到了20个,且连续发送了20个确认报文段给发送方,而发送方在接到确认报文段后会发现数量不对,而知晓网络已经变得拥塞。
- 这时候,cwnd数值将会从24变成0,同时慢开始门限数值也会变成原先cwnd数值的一半,也就是12,然后cwnd数值开始重新的进入慢开始进行增长,直到cwnd数值和慢开始门限数值一样,在进入到拥塞避免状态。
快重传:
假设,需要发送6个数据报文段,且需要按照顺序发送,当发送方发送了 1号数据报文段后,发送方需要等待接收方发送1号确认报文段,但是快重传可以让发送方在发送完1号数据报文段,等待接收方返回确认报文段的这个时间段内,发送2号数据报文段。
于是就会出现,发送方发送完1号数据报文段后,直接发送2号数据报文段,紧接着在发送3号数据报文段。
再假设,如果接收方没有接收到3号数据报文段,而是收到了4号数据报文段,那么接收方会朝发送方发送一个重复确认报文段,也就是重复的2号确认报文段。
而发送方因为快重传的原因,会在4号数据报文段发送后连续发送,所以接收方会接连收到5号数据报文段,和6号数据报文段,同时接收方在接收到5号和6号数据报文段后,会接连朝发送方发送两个 2号确认报文段。
当发送方接连发送3个重复的2号确认报文段后,发送方会意识到3号数据报文段没有被成功的接收,所以会发送3号数据报文段,当3号数据报文段被接收后,接收方会发送一个6号确认报文段,表示6个数据都已经成功的接收。