目录
0.TCP协议格式
编辑
一.确认应答(安全机制)
二.超时重传(安全机制)
1.SYN丢包
2.ACK丢包
三.连接管理(安全机制)
1.三次握手建立连接
编辑
2.四次挥手断开连接
3.建立和断开连接
四.滑动窗口(效率机制)
五.流量控制(效率机制)
六.拥塞控制(安全机制)
七.延迟应答(效率机制)
八.捎带应答(效率机制)
九.面向字节流
1.粘包问题
2.具体的现象
3.解决方案
1.在消息末尾加上特殊的分隔符来标识消息的结束
2.使用一个专门用来描述消息体长度的字段,来标识消息体的具体长度
十.TCP异常情况
1.程序崩溃
2.正常关机
3.主机掉电操作
4.网线断开
十一.常见面试题
传输层协议
如果我们给一个人发送多条信息,由于网络的问题,可能会出现,乱序的问题.比如我们发送两条信息:1.你好.2.吃了吗? 由于网络问题,可能会出现接收方先接受到了"吃了吗?",后接受到了"你好.",这样的情况我们是不想出现的,因此确认应答机制可以很好的解决这种问题.
如下图,为了解决这种问题,每次发送消息的时候,TCP数据中的字节进行了编号,比如主机B接受到了1-1000byte的数据,32位序列号中1-1000标志已经接受到了1000个字节,确认序列号返回1001,表示下次从第1001个字节进行发送.
主机A发送数据(SYN)给主机B,可能由于网络拥挤等原因,消息无法到达主机B,因此主机B也不会给主机A发送确认应发ACK.如果主机A特定时间内没有接收到主机B发送来的确认应答ACK,就会将上次的数据进行重发
主机B接受到了主机A的数据,并且发送了确认应答ACK,但是由于网络拥堵等原因,ACK发送了丢包,主机A并没有主机B发送来的ACK应答.
这个时候也会触发超时重传机制.由于我们发送的消息主机B已经接受到了主机A发送的数据,只不过ACK应答丢包.主机B没有必要存储重复的数据,因此第二次发送消息的时候(超时重传),可以利用前面提到的序列号(前面一次发送序列号已经保存,第二次发送的时候已经存在这个序列号了),就可以很容易做到去重的效果,主机B只需要发送一个确认应答的ACK就可以了.
对于网络通信来说,三次握手可以检查双发的收发能力是否正常,例如高铁每天都会空跑一趟.
从下图可以看出,通过两次SYN和ACK的过程可以确保双方的收发能力都没有问题,在这个基础上就可以进行正常的数据发送和接收
由于接收方的ACK和SYN可以合并为一次通信完成(都是在传输层进行发送,在后面的捎带机制也有讲解),提高了效率,四次握手可以简化为三次握手
三次握手标志位发生的变化
发送方发送断开连接,被接收方接收和应答,接收方会做一些断开前的准备工作.
一般来说FIN是由应用程序发起的,比如调用close()方法,所以是应用层面的,之后接收到发送方ACK应答,服务器就可以释放资源
为什么断开连接四次挥手不能转变为三次?
第一个ACK是操作系统(传输层)实现的TCP应答,第二个FIN是应用程序层面的,这两个操作是有时间差的,大概率是不会合并在一起的.
因此,我们设计了滑动窗口,一次发送特定数目的数据,可以大大提高效率.下面的案例窗口的大小为4,即一次可以发送四条SYN请求,当主机A接收到主机B发送的ACK应答的时候,滑动窗口向下进行移动,此时可以发送下一条的数据(4001--5000).
那如果发生了丢包的问题,该如何解决呢?下面还是分两种情况进行考虑.
情况一:数据包已经抵达,ACK被丢了。
这种情况下,部分ACK丢包了不要紧,可以根据后面的ACK进行确定.
比如确定序列为1001的ACK丢包了,但是后面2001的ACK应答被主机A成功接收了,我们可以根据这个应答确定前面的数据(1001)都已经接收了,因为如果没有接收到1--1000数据,序列号不会改变,就不会发送2001的ACK应答.
现实案例:别人问你学历,你说是初中,这说明你已经上过小学了.
考虑一下,如果最后一次ACK丢包,会发生什么情况?这个时候后面已经没有ACK应答了,因此这个时候我们只能触发超时重传完成最后一次的SYN和ACK应答.
情况二:数据包就直接丢了。
这种机制被称为 "高速重发控制"(也叫 "快重传")。
主要是确定滑动窗口的大小,通过发送方与接收方动态协商来确认
每个程序在启动的时候都会去申请系统资源,发送和接收方缓冲区就是申请来的资源.
每次进行ACK应答的时候,ACK应答中将剩余空间的大小放在16位窗口大小,表示具体可以接收多少数据,通过接收方反制发送方对窗口大小的限制,发送方不能为了提高效率而无限的扩展窗口的大小.
如果接收方的处理能力比较低,可能会出现缓冲区装满的情况,这个时候窗口的大小变为0,这个时候发送方不能再发送数据给接收.
解决窗口大小问题
虽然TCP有了滑动窗口这个大杀器,能够高效可靠的发送大量的数据。但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题。
因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。
TCP引入 慢启动 机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据;
具体窗口的大小以以下两个因素决定:①接收方缓存区的大小 ②拥塞控制中根据网络的状态确定下来的窗口大小 我们一般取两者的较小值作为实际窗口的大小
少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;
当TCP通信开始后,网络吞吐量会逐渐上升;随着网络发生拥堵,吞吐量会立刻下降;
拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。
如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小
可以选择以下两种情况来进行延迟应答:
比如我们可以每两次请求,应答一次,比如第2,4,6应答.如果是偶数次请求,可以完成应答,如果是奇数次应答,那么最后一次就采用时间限制,超过一个系统默认的时间就应答.
由于延迟应答的存在,可能存在SYN报文和ACK报文同时发送的情况那么系统就会把两个报文合二为一(这就是三次握手建立连接可以把第一次ACK和第二次SYN合并在一起的原因)
在面向字节流中会出现的一个问题就是粘包问题
当发送方将数据发送给接受方的时候,发送的数据是以二进制(Java中的byte数组)进行传输的.接收方接受到之后,会存储到接收方的缓冲区中,发送方将多条数据发送给接收方,这多条数据一起存储到缓冲区中,此时如果我们不采取任何方式,多条数据存储到一块,这种不能有效区分消息边界的现象叫做粘包
如何解决粘包问题其实就是如何区分这些消息的边界.
比如我们在每条消息的末尾加上\n来作为一条消息的结束.
你好啊,一会去吃火锅吧!!!\nHow are you.\n不回信息你是个猪吗?\n
在获取消息的时候我们可以使用特殊字符截取缓冲区的内容
1.读取消息的时候,先把4byte的表示消息体长度的字段读取出来,比如第一个长度为:42
2.继续在缓冲区读取42个字节,这42个字节表示消息的内容
3.在读取4个byte的下一个消息的长度,重复上面操作.
举例:
JSON,用大括号来包裹消息,那么就可以理解为他是使用大括号做为特殊字符来表示消息结尾的HTTP,应用层的协议,既使用分隔符也使用了表示消息长度的字段解决粘包问题
操作系统是会感知到的,可以做相应的处理
操作系统会回收进程的资源,其中释放包括文件描述符表,就想当于调用了对应socket的close之后触发FIN操作,进而开始进入四次挥手,和普通的四次挥手没有区别.
通过开始菜单或执行关机命令,系统会强制结所有进程,回收资源,与程序崩溃执行的流程类似
系统不会做出任何反应
与主机掉电的情况相同,只不过是主机都是正常工作的
1.简述下三次握手,四次挥手的流程
上面已经讲解了,可以自行去看
2.为什么需要三次握手,两次不行吗?
上面已经讲解了,可以自行去看
3. UDP本身是无连接,不可靠,面向数据报的协议,如果要基于传输层UDP协议,来实现一个可靠传输,应该怎样设计?
4.UDP大小是受限的,如果要基于传输层UDP协议,传输超过64K的数据,应该如何设计?
问题三和问题四都可以基于TCP安全和效率机制进行回答,比如:
引入序列号,保证数据顺序;
引入确认应答,确保对端收到了数据;
引入超时重传,如果隔一段时间没有应答,就重发数据;
5.TCP和UDP的对比和区别.
TCP用于可靠传输的情况,应用于文件传输,重要状态更新等场景;
UDP用于对高速传输和实时性要求较高的通信领域,例如,早期的QQ,视频传输等。 另外UDP可以用于广播;