网络原理 - TCP/IP
文章目录
- [网络原理 - TCP/IP](#网络原理 - TCP/IP)
- 前言
- 一、应用层自定义协议流程
- 二、传输层协议
- TCP核心机制介绍
- 经典面试题
- 总结
前言
一、应用层自定义协议流程
确定传输的数据信息
确定传输的数据格式
- 跟据需求 , 确定交互信息有哪些 , 请求 , 响应
- 组织好数据格式
组织数据格式 , 现在比较流行的
-
xml(带宽消耗太多
-
json(当前流行的方案之一
请求
{
userId:1234,
position:"123E45N"
}
- google protobuf(也是当前流行的方案之一 ,但是可读性差一点 , 是二进制的
除了自定义协议之外 , 还有大佬们研究好的现成的协议 : HTTP协议
二、传输层协议
UDP , TCP
- UDP协议格式
每个协议都是报头+载荷
载荷就是应用程序包 , 应用程序包就是前面构造的XML格式的数据包或者是Json这样的数据包
前面要加一个报头
4各部分 ,每个部分2字节
第一各部分 , 16位源端口号
第二个部分16位目的端口号
问题:一个进程能否绑定多个端口号
能 , 工作中很常见 , 一个socket绑定到一个端口 , 一个进程可以创建多个socket
问题 :一个端口号的是否可以被多个进程绑定
我们认为是不能的
第三个部分叫做UDP长度 , 整个报文长度 , 包含包头加载荷
UDP最大传输长度64KB , 如果超出 , 就会截断
如何解决
- 应用层拆包组包
本来一次相应返回10条广告 , 拆成两个UDP数据报 , 各自返回5条广告
但实现成本高 , 网路传输可能会出现问题 , 会丢包 , 会顺序错乱
建议换成TCP , TCP对于单个数据报的`长度没有限制
UDP当前使用的时候提前预估 你的数据有多长
第四个部分 , 16位UDP检验和
验证传输数据是否出错
发送之前把数据准备好了 , 把这个数据每个字节代入到"公式"计算得到结果 , 校验和
发送时把数据和校验和一起发送
接收方收到数据和校验和
接收方把数据代入到同样的公式计算得到结果再继续校验
udp适用于本身不容易丢包,对传输效率要求高的
- TCP
16位源端口号,16位目的端口号
32位序号
针对传输数据进行编号,第一个字节的编号
32位确认序号
给ack(应答)报文使用,关联这个ack是应答那个数据 最后一个字节的编号加一
Tcp包头长度是不固定到,因为
选项 长度是不固定的
剩下是20字节
4位首部长度 表示TCP报头长度 4bit(就是1111)表示范围是0-15,单位是4字节,因此选项的长度是4的倍数,首部最大长度是60,
保留(6位 ) 现在不用,先占个位置,说不定以后会用,以后扩展的时候,方便
6个标志位,
16位创客大小
16位校验和,和UDP差不多
16位紧急指针
选项
TCP核心机制介绍
可靠传输 和代码关系不大,TCP内部支持实现机制
可靠传输不是100%能够送达消息给对方,
但知道对方是否收到
1 确认应答
核心机制1,确认应答,实现可靠传输的核心机制
怎么做到 考确认应答
后发先至情况出现原因
传输数据的顺序错了,解决,引入编号,重新排队,但TCP是面向字节流的 ,不存在第一条第二条这样的概念,因此针对字节进行编号
应答报文和响应区别
2.超时重传
丢包,发现达到一定时间没有返回ack,重现传一下,重传次数越多,到达概率越大
包会丢,ack也会丢
主机不知道哪个丢了,只知道ack没有返回,所以会重传数据
有问题
如果这个数据是扣款操作,完蛋了
重传动作是操作系统内核自动触发,和应用程序无关
传输的数据也是先到达接收方的操作系统内核
对于接收方来说,内核会给TCP的socket分配一个"接收缓冲区"(内存空间
接收方的应用程序调用read这样的操作把缓存中的数据取走
重传的数据到达缓存,接收方会根据序号进行去重,新数据丢掉
所以应用程序仍然是读到一份数据,因此不会重复扣款
数据重新排队的过程,也是在接受缓冲区中进行的
TCP,解决了可靠性,也解决了数据传输顺序。数据重复传输的问题
重传达到一定次数发送方认为是网络故障,放弃当前TCP连接,
超时重传和确认应答,是TCP实现可靠传输的核心机制
网上很多资料是错的,说TCP可靠传输核心机制是三次握手 错!
3.连接管理(面试常考
建立连接断开连接是操作系统内核完成的
面试常考
TCP如何建立连接的?如何断开连接的
建立连接流程为"三次握手"
握手:不包含业务数据的数据包,没有载荷
业务:应用程序中实现的一些功能
握手流程
客户端发送syn(同步报文)给服务器
只有爆头,没有载荷,这样的豹纹需要标志一下
TCP六个标志位里面第五个标志位syn设为一
确认应答同样存在ack返回,也相当于一次握手
服务器返回ack
服务端也发送给你syn
客户端返回ack
三次握手,这不是4次?
服务器ack syn合并成一次
ack为1,就是应答报文
同时syn为1,就是同步报文
及时应答也是发送连接
合并原因:效率
网络传输需要一系列封装分用
多线程的同步含义其实是互斥
TCP的同步含义,是通知

画图
三次握手意义是什么
1、初步验证通信是否通畅,后续可靠传输大前提
2、也是在验证通信双方发送能力和接收能力是否正常
3,协商关键参数 ,三次握手进行必要协商,比如32位序号序号起始数值
32位序号不是从一开始,数据传输的时候有一个包没有传输到,再次连接的时候到了,不应该处理,通过32位序号判断
tcp的三次握手是在验证当前环境是否符合可靠传输的前提
断开连接
四次挥手 和握手类似,都只有报头
没有载荷,没有业务
断开连接客户端和服务器都可能先发起
假设客户端先发fin
fin就是第六位标志位
1发送fin,2发ack,2发fin,1再发ack
这里中间两步能不能合并?
不一定!
建立连接的时候,ack和syn都是操作系统控制,是相同时机,因此可以控制
ack返回时机是内核控制,收到fin后触发
fin返回时机是应用程序控制,应用调用socket.close才会触发fin
socket接收到fin信息,到close之间的时间可能还有几百毫秒,因为有别的逻辑
时机不同,合并不了
4.滑动窗口
为提高效率,前面的"可靠效率"对效率是有损伤的
只是减少损失
批量传输一个大小,称为窗口大小,收到头一组的,窗口向后挪动
不会影响可靠传输
丢包如何处理
ack丢包,不需要处理,ack的确认序号,后一个能包含前一个,证明前一个已经到达
数据丢包
1到7千的数据,1001到2千丢了,连续发几个其他序号的数据,但是反馈的确认序号都是1001的,那么就能证明1001丢了就
需要快速重传,会重传1001到2千这个数据,这个数据一补齐后,接下来所要的就是7001
5.流量控制
流量控制就是对滑动窗口大小进行控制,否则流窗口特别大,传输的特别快,接收方处理不过来
数据进入缓冲区后,缓冲区满了缓冲区,不会自动扩容,只会让的新数据被丢弃
流量控制根据接收方的处理能力来反向限制发送方的发送速度,也就是窗口大小
,1.接收方的处理能力怎样衡量?
接收缓冲区剩余空间大小
2.衡量了之后,如何通知发送方做出限制?
把接受缓冲区剩余空间大小是通过ack通知发送方,就放在16位窗口大小的地方
上述机制保证的是TCP传输的可靠性,不是安全性TCP,是一个安全传输协议。这个说法是错误的
6.拥塞控制
和流量控制类似,都是对滑动窗口做出限制。流量控制依据接收方的处理能力应在控制依据通信路径的处理能力
刚开始按比较慢的速度发送数据,
没有丢包,加大速度,指数增长
窗口大小达到阈值,改为线性增长
增长一定程度,丢包了
丢包后窗口缩小
老式方案,回到慢开始状态,改为线性增长
新式方案,回到阈值,线性增长,新的阈值是丢包位置窗口大小/2
减小速度,窗口大小不是固定值,时刻动态变化,也就是动态平衡,而实际发送窗口大小,看两个控制的较小值
7.延时应答
在滑动窗口的基础上提高效率,如何让窗口大一点
它是根据剩下空间的大小来衡量,如果延迟返回,这个数据可能应用程序就消费了一部分,窗口大一点
同时返回ack数目也可以减小
8.捎带应答(配合延时应答)
因为有延时应答,返回ack的时候,就可以把ack和响应一起合并成一个数据包
Ack关键的只有包头,不需要载荷
响应数据,关键的是载荷
和四次挥手很像,四次挥手可能会三次,就是因为捎带应答
9.面向字节流
面向自节流的过程中,可能涉及到粘包
zhan nian,这两个音都有
TCP的缓存区里面数据包和包之间边界不明显,但凡是自己留的方式,传输都涉及粘包问题
Udp也有缓冲区,但它有节点,每一个节点都是一个datagram packet
解决方案,
1.引入分隔符,特殊符号作为包的结束或者开头标记
2.在数据开头的地方添加一个固定的属性,表示数据包的长度
如果使用线程框架框架一般把这个就处理好
除非我们修改框架,基于TCP原生开发
10.异常情况
1.进程崩溃
和四次挥手完全相同,
正常通过close触发,
进程退出,操作系统自动对文件资源进行释放(操作系统清理PCB,PCB中的文件描述表),等价于调用close
进程没了 连接还在,还可以处理后续挥手过程
2.主机关机(正常流程关机)
先强制结束所有应用程序,相当于进程崩溃
正常关机会用一段时间足够四次挥手完成
如果挥手没有完成
发送fin后,关机了
服务器正常发送ack和fin,但是他不会再收到ack了,再重传多次fin后还没有ack单方面放弃连接,服务器会把自己持有的客户端信息删掉
3.主机关机(掉电)
电源没了直接关机
接收方掉电,ACK无了,发送放超市存储经过几次重传之后,没有ack,发送方只放弃连接,给对方复位报文,六个标志位第四位RST
发送方突然沉默,解除后无法区分什么情况,是对方挂了还是休息一会?
接收方周期性给对方发一个"心跳包"
不携带业务,只为了触发一次ack
没有ack,噶了,接收方主动断开连接
心跳包是TCP常见的
但我们一般自己实现这样的机制,因为TCP太慢了
4.网线断开
发送方,就相当于,主机关机第一种情况
接送放,主机关机第二种情况
TCP常用状态
LISTEN 服务器持有状态,
服务器准备就绪,随时可以有客户端连上
连接时的状态
ESTABLISHED 这个是客户端和服务器端都会涉及到的状态,表示链接已经建立,接下来可以进行网络通信了
断开连接状态
CLOSE_WAIT
断开连接的时候收到FIN的一方会进入的状态
收到FIN进入这个状态,直到一方主动发出FIN
服务器上出现了很多这个状态,就是出现bug了
TIMA_WAIT
主动断开连接一方会进入的状态,等待一定时间处理最后一个ACK丢包的情况,或者重传,如果此时他彻底释放TCP连接的话,重传的fin就没人能处理了,没有人能返回ack了
等待时间是2MSL
MSL,表示网络传输过程中,从一端到另一端的最大理论时间,一般来说,默认时间是一min
如果服务器上存在大量的time wait,此时意味着大量的链接都是服务器主动断开的
服务器可以转,客户端可以看,看看自己代码怎么写的,掂量掂量是不是出现bug
TCP层和应用层要区分好
就像断开连接和拒绝访问
断开连接是TCP层
拒绝访问是应用层
六个标志位,剩下两个
URG,表示紧急指针有效
正常来说,按顺序读取紧急指针是插队,让后面的被读取。根据16位紧急指针来看从哪开始读
这个机制现在已经不用了
PSH催促标志位,尽快交给应用程序
但也没啥用
选项是,根据不同操作区分,这里面的用途
经典面试题
如何基于udp实现可靠传输?
照搬TCP机制
应答机制,后发先至,序号,排序去重,丢包超时重传,建立连接先看是否通畅,三次握手,再进一步提高效率,滑动窗口,延时应答,捎带应答,流量应答,拥塞控制
TCP可靠
UDP性能高