核心机制:面向字节流
面向字节流
读取/写入的时候,读写操作有很多方式,非常灵活
读 100 字节
1.一次读 10个字节,10次完成
2.一次读 20 个字节,5次完成
3.一次读 50 个字节,2次完成
粘包问题
接收方分用的时候,去掉报头,把载荷内容放到一个,接受缓冲区中
接受方的应用程序,read 的时候,就有很多种 read 的可能性
read 的可能性:
1)a a a b b b c c c
2)aa ab bb cc c
3)aaa bbb ccc
4)aaab bbbc c
5) aa abb bcc c
怎么 read 是取决于应用程序的代码是咋写的
具体怎么来读,才能确保读到的是一个"完整的应用层数据包"
粘包,粘的是应用层的数据包
TCP 字节的特效,收到多个 TCP 数据报的时候把所有的载荷都给混到一起,放到接受缓冲区里
包的边界比较模糊,就好像是"粘上了一样"
粘包问题就是咱们非常需要关心的问题
1.通过特殊的分隔符,来作为包边界的区分
比如, 约定每个应用层数据包,都已 ; 结尾
包的数据里面,不能包含分隔符,需要找到合适的符号,确保这个符号在正文中不会重复出现,即使 ascil 码表中,也有不少的字符,可以用来作为分隔符的,有一下特殊的"不可见字符"历史遗留问题
在比如,之前写的回显服务器,当时是使用 \n 作为分隔符的
String request = sacnner.next(); => 读到空白符就结束了,空白符是统称,包括但是不限于:空格,换行,回车,制表符,分页符,垂直制表符
writer.println(request) => 发送请求的时候,使用 \n 作为结束标记的,由于是通过控制台来进行控制输入的请求内容的,控制台输入的内容本来就不会包含 \n
2.在应用层数据包开头的地方,通过固定长度,约定整个应用层数据包的长度
应用程序, read 的时候,先固定 read 2个字节,看看 2 个字节里面的内容是啥 => 发现是3接下来再 read 3 个字节,读到的 aaa 就是完整的应用层数据包
粘包问题只是针对字节流的传输.对于文件的操作,(使用文件存储多个结构性数据,也是可能涉及到粘包问题的)
比如,通过文件,保存若干个 学生信息
class Student {
name
id
age
}
比如约定成,每个学生信息占一行(使用 \n 作为结束标记,作为分隔符)
对于 UDP 来说不存在粘包问题 UDP 的接受缓冲区和 TCP 的不太一样
应用层不需要做区分,应用层每次调用 recv 得到的就是一个完整的 DatagramPackage 也就对应一个完整的 应用层数据包
核心机制 异常情况
1.进程崩溃 [正常流程]
进程崩溃,意味着对应的文件描述符就被关闭了(调用 close,干掉进程) 只要是进程退出,都会释放 PCB,释放文件描述符表 触发 FIN
TCP 的连接并没有因为进程的结束立即结束,保留一会
2.主机关机 [正常流程]
正常流程下的主机关机,就会先杀死所有的进程,此时也会触发 FIN, 进而进入四次挥手,有可能挥不完
如果关机的速度比较慢,有很大可能四次挥手就挥完了
如果关机的速度比较快,刚发 FIN,机器就关了
对端可以正常返回 ack ,也会继续正常发送 FIN,这里的 FIN 就没有收到 ack,尝试几次重传 FIN 还是没有 ack,对端就直接放弃连接(删除之前保存的对端信息)
四次挥手,如果挥完了,双方可以确认,双发都能顺利吧保存的信息删掉
如果挥不完,至少直接可以把保存的信息删除掉,对端的就不管了
此时对端关机了,内存的数据全没了
3.主机掉电(直接拔电源)
直接啥都没了.来不及 FIN
1)如果掉电的一方是接受方,对方是发送方
对方继续发送数据,没有 ack =>超时重传 =>仍然没有 ack => 继续超时重传,达到一定的程度,掉电方仍然没有 ack ,发送方发送一个 复位报文,就是表示要重置连接放弃当前的连接
2)如果掉电的一方是发送方,对方是接受方
接受方感受到的是,发送方突然停下来了,接受方会继续阻塞等待,等待发送方发来新的数据(心跳包)
心跳包
接受方会周期性的和发送方交换"心跳包"
A 给 B 发一个无业务数据的报文
B 给 A 返回一个 ack
如果对方有应答,就可以认为对方是正常工作的
如果心跳包也没有应答,就可以认为,对方挂了
发现心跳包没有,就可以单方面的释放连接了(这个机制非常重要,尤其是分布式系统中,分布式系统中,知道,某个节点存活,非常重要)
TCP 协议自身虽然提供了心跳,心跳周期比较长,而在实际开发中,需要更高频的心跳应用层,代码实现的
4.网线断开
本质上是和主机掉电是一样的.
网线断卡的两端,一个是发送方,一个是接受方
对于发送方来说,没有 ack => 超时重传 => 仍然没有 ack => 超时重传 => 达到一定程度放弃连接
对于接受方来说,周期性触发心跳包 => 发现对端下线 => 放弃连接
1.确认应答
2.超时重传
3.连接管理(三次握手,四次挥手)
4.滑动窗口(快速重传)
5.流量控制
6.拥塞控制
7.延时应答
8.捎带应答
9.面向字节流(粘包关系)
10.异常情况(心跳包)
这只是 TCP 协议的十大核心机制,TCP 还有其他机制
URG :表示"紧急指针"有效,正常情况下,TCP 的数据都是"顺序传输" 1- 1000, 1001- 2000,...., 紧急指针意味着后面有一些数据要先传输(插队),紧急指针的值表示,从当前位置往后多少个字节位置的部分,要进行插队的(使用比较少)
ACK: 应答报文
PSH:崔楚对方,尽快把缓冲区的数据交给应用程序
RST:复位报文
SYN:同步报文
FIN:结束报文