目录
UDP协议
UDP协议的报文格式:

16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度。UDP报文长度占两个字节,16位表示的数据范围(0-65535)也就是64kb,UDP数据报最大长度就是64kb。
校验和:因为网络传输中,由于一些外部干扰,数据传输可能会出现出错的情况,网络传输主要是光信号和电信号,由于电磁场、高能离子等,就可能出现比特翻转。因此就需要能识别出出错的数据,所以就有了校验和。
校验和本质上其实也是一个字符串,是通过原始数据生成的体积比原始数据更小,原始数据相同得到的校验和就一定相同,反之,校验和相同那么原始数据大概率也是相同的(不相同的概率忽略不计)。
数据发送之前,先把整个数据包的数据都代入计算一个校验和,把数据和校验和一起发送给对端。接收方收到之后重新计算一下校验和,和收到的校验和进行对比(UDP发现校验和不一致,就会直接丢弃)
UDP的特点:
**无连接:**UDP协议本身不会存储对端的信息,发送数据的时候要显示指定对端的IP和端口号,不需要建立连接。
**不可靠传输:**没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。
**面向数据报:**应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。
**全双工:**UDP的socket既能读也能写。
大小受限:UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)
缓冲区:UDP没有真正意义上的 发送缓冲区。发送的数据会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃。
TCP协议
TCP的结构:

源端口号和目的端口号就是说数据从哪里来到哪里去。
4位首部长度:TCP报头的长度是不固定的报头最短是20字节(没有选项),报头最长是60字节(选项最多是40字节)。
4 bit 范围是 0-15,而是使用的是 "4字节为单位",不是使用字节为单位。所以,固定部分是20,选项部分最多是40
校验和:和UDP协议一样。
保留位:因为UDP的长度是64kb,我们无法改变,所以发明TCP的人做出了改变,加入了保留位,先占个位置,如果后面需要就可以进行扩展使用。
TCP的特点
1.有连接:发送方和接收方会保留对方的信息(如果A和B建立连接,B拒绝了,就无法建立连接,通信就无法完成)
2.可靠传输:A给B发消息,消息有没有成功送达A可以感知到(如果发送失败就可以进行采取一定的措施)
3.面向字节流:TCP的传输和文件操作一样都是以字节为单位的
4.全双工:一个通道允许双向通信就是全双工反之就是半双工(一个socket对象既可以发送数据也能接收数据)
TCP的核心就是可靠传输
TCP的核心机制
TCP如何保证可靠传输:
核心机制一:确认应答(可靠机制)
发送方把数据发送给接收方后,接收方收到数据之后就会给发送方返回一个应答报文(acknowledge 简称 ack),发送方收到应答报文后就知道自己的数据发送成功了。
每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发。

引入序号之后,接收方就可以根据序号对数据进行排序
TCP在接收方会安排 "接收缓冲区"(内存,操作系统内核里)通过网卡读到的数据,先放到接收缓冲区中,后续代码里调用 read,也是从接受缓冲区来读的
缓冲区根据序号来排序,序号小的在前面,大的在后面,确保前面的数据已经到了,然后read才能接触阻塞,如果是后面的数据先到,read继续阻塞,不会读取到数据
如何确认一个数据包是普通数据还是ack数据呢?
上面的TCP结构图中ACK为1,就表示当前数据包是一个应答报文,此时该数据包中的确认序号字段才能生效,如果这一位为0,则表示当前数据包是一个普通报文,此时该数据包中的确认序号字段不会生效。
通过特殊的ack数据包里携带的确认序号告诉发送方哪些数据已经被收到了,此时发送方就知道自己刚刚发送的数据是否成功。TCP的初心就是可靠传输,达成可靠传输的核心机制是确认应答。
核心机制二:超时重传(可靠机制)
A发送数据给B后,可能因为网络拥堵等原因,数据无法到达B;如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了。
确认应答是一个比较理想的情况,如果网络传输过程中,出现了丢包该怎么办?
首先我们要知道丢包的原因:
如果我们把网络想象成错综复杂的公路,在公路上就会有很多收费站,正常情况如果车流量不大,车辆都能正常通过,但是如果节假日就会发生堵车的情况,这种情况车辆就没办法正常通过。在网络中我们可以把收费站理解成 "路由器/交换机" 如果数据包太多,就会在路由器/交换机中出现 "堵车" 的情况,但是路由器/交换机针对 "堵车" 的情况是比较粗暴的,它会把数据包直接丢掉,此时这个数据包就在网络上消失了。这也就是我们所说的丢包。
丢包是一个随机事件,因此在TCP传输过程中存在两种情况:
无论是哪一种情况,A都会重新传输,如果丢包的概率是10%,再重传一次,两次都丢包的概率就是1%,传输成功的概率是很大的,重传操作大幅度提升了数据传输成功率。
那么发送方何时进行重传呢?
发送方,发出数据后,会等待一段时间,如果这个时间内没有收到ack就会触发重传。
初始的等待时间是可以配置的,也可以动态变化,每经历一次超时重传,下次的等待时间就会变长。但是也不是无限变长,超时重传次数达到一定程度/等待时间达到一定程度就认为网络出现严重故障,放弃这一次传输
如果传输的时候ack丢了,触发了超时重传,那么接收方收到了两条一样的数据这样会不会给带来bug呢?
TCP有一个接收缓冲区(一个内存空间)会保留已经收到的数据和数据的序号,接收方如果发现,当前发送方发来的数据是已经在接收缓冲区中,接收方就会直接把这个后来的的数据丢弃掉,以确保读的时候只读到一条数据。
接收缓冲区不仅可以去重,还能进行排序,确保发送的顺序。
确认应答和超时重传,是TCP协议中最核心的两个机制,保证了TCP能够进行可靠传输
问:保证TCP可靠传输的关键机制是三次握手吗
答:不是,是 确认应答﹢超时重传,三次握手的可靠性也是要靠确认应答和超时重传的
核心机制三:连接管理(可靠机制)
连接管理:建立连接(TCP三次握手)+ 断开连接(TCP四次挥手)
TCP三次握手
TCP在连接过程中,通信双方一共需要 "打三次招呼" 才能建立连接。
握手(handshake),握手操作指的是没有实际的业务,只是"打个招呼"。发送一个不携带业务的数据,通过这个数据和对方 "打个招呼"
HTTPS,获取证书,验证证书,加密对称密钥,传输对称密钥,确认对称密钥收到等,这些就是SSL协议的 "握手流程"

三次握手时服务器和客户端的状态:

closed:不存在的状态,tcp 还没有连接
listen:服务器启动,随时可以有客户端连上来(new ServerSocket的时候,就会进入 listen 状态)
syn_sent / syn_rcvo:这两个状态的存在时间非常短,正常情况下是看不动这两个状态的
eatablished:连接建立完毕,随时可以发送数据
问:为什么要握手三次,握两次或四次行不行?
答:握四次没必要,握两次不足以完成验证发送方和接收方的接收能力和发送能力。
第一次握手后,服务器(B)知道了自己可以成功接收数据,客户端(A)可以成功发送数据,但 A 不知道;第二次握手后,A知道自己可以成功发送数据和接收数据,但是B只知道自己可以成功接收数据,并不知道自己是否可以成功发送数据;第三次握手后,B就知道自己成功发送了数据。此时握手完成,此时A和B记录了对方的信息
三次握手的核心作用:
-
确认当前网络是否通畅
-
让发送方和接收方都知道知道的接收能力和发送能力是否正常
-
让双方在握手过程中针对一些重要的参数进行协商
TCP四次挥手
断开连接(客户端和服务器都可以发起)

TCP四次挥手可以把中间的两次合二为一吗?
不一定
不能合并的原因是ack和第二个fin触发的时机不同,ack是内核响应的(B收到fin会立即返回ack),而第二个fin是应用程序的代码触发的,从服务器收到fin(同时返回ack)再到执行到发起fin的代码,这中间要经历的时间是不确定的。
TCP三次握手的ack和第二个syn都是内核触发的,同一时机,所以可以合并。
三次握手,一定是客户端主动发起syn (第一次握手,一定是客户端开头的)四次挥手,客户端和服务器,都可以主动发起FIN(就看是谁先调用close),但是实际情况下,还是客户端断开连接的可能性更大
四次挥手时服务器和客户端的状态:
TIME_WAIT:主动发起FIN的一方,就会进入到TIME_WAIT
CLOSE_WAIT:被动发起FIN的一方,就会进入CLOSE_WAIT
进入CLOSE_WAIT 状态时,服务器正在等待应用程序代码调用close方法。
CLOSE_WAIT 正常开发中,应该是看不到的。原则上来说,感知到对方断开之后,就应该尽快的执行close ,如果发现服务器存在大量的 CLOSE_WAIT,而且持续时间很长,此时意味着代码大概率有bug(检查是否执行到close了)
TIME_WAIT:连接终止时主动关闭方进入的等待状态,持续时间为2MSL(假设网络上任意两个节点通信消耗的最大时间为MSL,TIME_WAIT等待的时间就是2MSL)
假设出现这样的情况:如果B给A发FIN,A收到之后,返回ACK就把连接释放了,但此时这个ACK丢包了,B就会重传FIN,此时就无人来处理重传的FIN了
所以 A 这边 FIN 之后不能立即释放连接,而是要等一下,等对方是否可能会重传FIN(最后一个ACK是可能丢包的),多等一会,确认确实对方不会重传FIN再释放