赞
踩
一、传输层
1.UDP(适用于要求可靠性不太高,但效率很高的场景)
1)无连接
2)不可靠
3)面向数据报
2.TCP(要求可靠性高)
1)有连接
2)可靠传输
3)面向字节流
TCP的10个重要特性:(保证可靠传输)
第①个:确认应答(可靠传输的最核心机制)
TCP是面向字节流的,此处的编号是按照字节来编号的(每个字节有一个自己的编号)
应答报文,本质是ACK字段为1的报文,此时报头中的“确认序号”才是生效的
第②个:超时重传
确认应答是理想情况。数据在传输过程中可能会丢包的。
当发送一条数据之后,TCP内部就会自动启动一个定时器,达到一定时间也没收到ACK,定时器就会触发重传消息
此时隔得时间更长,节省带宽。
如果是发送方发的请求丢了,重传是没有问题。
如果是接收方回复的ACK丢了,意味着对方收到了相同的数据,TCP会在内部进行数据去重(以序号为key,从而保证应用层读到的数据不是重复数据。
第③个:连接管理
a)建立连接,三次握手
建立连接的原因:1.更好的保证可靠性:建立连接的过程其实就是让通信双方验证各自的发送能力和接受能力是否正常。
2.协商一些重要参数
建立连接过程:
SYN 同步报文段,尝试和对方建立连接(Java Socket API中客户端new Socket(ip,port)内核就会发起这样的SYN请求
SYN这个标志位为1,表示这是一个同步报文段。
接受方会给发送方发送ACK和SYN,之后发送方在发给接收方一份ACK
总结:建立连接过程中,相当于通信双方各自给对方发送SYN,再各自给对方发送ACK,只不过中间的ACK和SYN合二为一了,于是就为三次握手
四次握手可以但没有必要。(效率低)
在建立过程中,ACK和SYN都是内核决定的,时间上是同意时刻发送的,所以就可以合并在一起。
建立连接和断开连接都可能会丢包,丢包就会触发超时重传。
几个重要的状态:
1.LISTEN:服务器启动完毕,随时可以有客户端建立连接(new SeverSocket(9090))
2.SYN_SEND/SYN_RCVD:建立连接的中间过程,如果连接建立的顺利,这两个状态一瞬即逝
3.ESTABLISHED:连接建立完毕,随时可以传输消息(验证了双方的发送和接受能力都正常,电话已经拨通,可以说正文了)(new Socket(ip,9090))
服务器调用new SeverSoket就会绑定端口号,并且进入LISTEN状态
客户端调用new Socket(ip,port)就会尝试和服务器建立连接并触发三次握手
①两次握手--不可以:无法判断自己的发送能力和对方的接受能力是否正常。
②四次握手--可以:中间的SYN和ACK是同一时机触发的,两个包合并成一个比较高效。
b)断开连接,四次挥手
双方各自向对方发起断开连接的请求,再各自给对方回应,只不过,中间的FIN和ACK不一定能合并在一起
因为中间两次操作的时机不一样。
①主机B发送ACK是内核自动完成的,内核收到FIN之后就会立刻发送ACK(ACK是收到FIN之后立刻由内核返回的数据包)
②虽然主机A发送了FIN,但是主机B的接收缓冲区中仍然可能有一些待处理数据。
此时要等到主机B把积压的数据处理完成后,调用socket的close方法的时候,才会发送FIN
①三次挥手--通常情况下不可以的:中间的ACK和FIN触发时机不一样。
如果触发了延时应答机制,就是可以三次挥完的。
·CLOSE_WAIT:(主机B的内核等待调用close方法)四次挥手挥了一半,当前可能挥了一半,剩下的两次就不挥了。(接收方没调用close方法,就会导致四次挥手只挥两次,从而没有正确关闭连接)
一旦发现机器上出现大量的CLOSE_WAIT状态,说明代码有bug
·TIME_WAIT:谁主动断开连接,谁进入TIME_WAIT状态,此时该主机已经完成了四次挥手的过程,但是仍然不能立刻释放连接,而要以TIME_WAIT状态来保持连接一段时间之后,再彻底释放连接。
这样做的目的是为了处理最后一个ACK丢包之后重传问题。
一旦最后一个ACK丢包了,主机B就无法区分是自己的FIN丢了,还是对方的ACK丢了。
如果主机A不保持连接一会,此时收到重传的FIN就无法应答ACK了。
保持时间会一直持续到对方不再会重传了,就会释放连接,真正进入CLOSED状态。
1)如果发现主机存在大量的TIMT_WAIT,这种情况不是BUG,会在一定时间之后自动消失。
2)即使进程结束,TIME_WAIT也不会随之消失。
·只要B收到FIN,就证明A的数据都已经传输完了。
·FIN_WAIT1是很短暂的状态,发送FIN的时候进入该状态,收到ACK的时候,进入FIN_WAIT2
如果对端没有发送FIN,此时主机A也就会始终在FIN_WAIT2,此时主机B就是CLOSE_WAIT
FIN_WAIT1(FIN-->)
CLOSE_WAIT(<--ACK)
FIN_WAIT2
LAST_ACK(<--FIN)
TIME_WAIT(ACK-->)
CLOSED
CLOSED
第④个:滑动窗口
在可靠性的前提下,进一步提高传输效率。
·滑动窗口本质上是批量传输数据,总的传输时间:N份数据传输时间重叠成了1份时间;N份应答传输时间,重叠成了1份时间。
·不等待ACK的情况下,批量发送的最大数据量,就叫“窗口大小”。窗口越大,传输效率越高。
·情况一:丢包的是ACK,不需要进行任何额外的处理。
·情况二:是数据包丢了,如果数据报丢了,主机B会返回的ACK一直都是丢了报的序列号,此处的重传只是重传丢了的数据,其他数据不需要额外重传:快速重传。搭配滑动窗口的超时重传。
·滑动窗口是发送方的概念,接收方只有一个接收缓冲区,没有“滑动窗口”概念。
接收缓冲区就是一个固定大小的内存空间,大小是固定的,可以通过内核的参数配置。如果接收缓冲区满了就不会继续传输,流量控制机制。
发送方窗口大小是动态变化的(流量控制+拥塞控制决定);接收缓冲区大小取决于内核的配置。
第⑤个:流量控制
·窗口大小不能无限大,传输速率太快,接收方可能处理不过来。
·流量控制本质是:根据接收方的处理能力来反向制衡发送方的发送速率。(窗口大小)
通过接收缓冲区的“剩余空间大小”来决定发送方的速率的。
·窗口大小,本质上就是接收缓冲区空余大小,这是应答报文中的报头字段里的字段。(16位窗口大小)
当窗口大小为0时,发送方会定时发送一个探测报文,因为接收缓冲区的数据随时可能被应用程序取走,一旦取走,就可以接收新的数据。
第⑥个:拥塞控制
·根据网络当前的拥堵情况,动态决定实际传输的窗口大小。
·窗口大小是由流量控制与拥塞控制共同决定的。
·实际发送方的滑动窗口大小=MIN(拥塞窗口大小||流量控制窗口大小)
·曲线图:1)从一个较小的窗口大小开始试探
2)如果没有发生拥堵(没有丢包)就指数扩大拥塞窗口
3)达到一定阈值后,线性增加窗口大小
4)一直到出现丢包,窗口回到初始值,调整阈值为出现丢包的窗口大小的一半。
第⑦个:延时应答
·目的是为了提高效率,在流量控制的基础上,尽量返回一个合理但比较大的窗口。
·延时的时间中就会给应用程序提供更多的消费数据的机会,此时时间到了,再发ACK的时候,得到的窗口大小(接收缓冲区的剩余空间就会更大一些)
延时应答的等待时间不能超过重传的时间。
第⑧个:捎带应答
·在延时应答的基础上,进一步提高程序运行效率的机制。
第⑨个:粘包问题
·严格讲不是TCP自身的机制,而是面向字节流传输所具备的共性问题
粘包,粘的应用层数据报,导致处理数据的时候,容易读取半个应用层数据报。
·通过应用层协议本身来区分包与包直接的边界,1)使用分隔符 2)明确包的长度
·在HTTP协议(基于TCP的应用层协议)中,两种方式都用到了
1)对于GET请求,分隔符就是空行
2)对于POST请求,Content-Length来指定包的长度
第⑩个:保活机制
·在一些“异常情况”下,TCP对于连接会有特殊处理
1)进程崩溃:这种情况下,TCP连接会正常四次挥手(只要进程退出,都自动关闭相关的文件)
2)主机关机(按照流程关机):关机的时间会强制先杀进程,杀进程的过程中就进行四次挥手
3)主机断电/网线断(重点):
a)接收方断电,对端尝试发送消息的时候,就会出现没有ACK的情况-->超时重传-->重传一定次数,重置连接-->放弃连接
b)发送方断电,对端尝试接收消息,对于接收方:
·“心跳包”:TCP的通信双方,即使在没有数据交互的过程中,也会定时相互传输一个没有实际业务意义的“心跳包”
只是为了证明双方可以正常交互,一旦隔了一段时间都没有收到对方的心跳包,就可以认为对端挂了。
总结:(基石)确认应答、超时重传、连接管理-->(提升程序效率)滑动窗口-->(保证可靠性,制约滑动窗口)流量控制、拥塞控制-->(进一步提升效率)延时应答-->(再次提升效率)捎带应答
粘包问题:和TCP不是强相关,而是和面向字节流强相关,涉及到应用层协议涉及的要点。
包活机制:保证可靠性在极端情况下仍然能生效
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。