
目录1. 网络基础概念2. 传输层重点协议2.1 TCP协议2.1.1 确认应答, 超时重传(安全机制)2.1.2 连接管理(安全机制)2.1.4 滑动窗口(效率机制)2.1.5 流量控制, 拥塞控制(效率机制)2.1.6 延迟应答, 捎带应答(效率机制)2.1.7 粘包问题2.2 UDP协议2.3 TCP/UDP对比1. 网络基础概念IP地址:是指互联网协议地址又译为网际协议地址, IP地址分为两个部分网络号和主机号127.*的IP地址用于本机环回测试通常是127.0.0.1端口号:端口号可以标识主机中发送数据、接收数据的进程。简单说端口号用于定位主机中的进程协议:网络协议的简称网络协议是网络通信即网络数据传输经过的所有网络设备都必须共同遵从的一组约定、规则。协议最终体现为在网络上传输的数据包的格式五元组:在TCP/IP协议中用五元组来标识一个网络通信: 源IP, 源端口号, 目标IP, 目标端口号, 协议号协议分层: 分层最大的好处类似于面向接口编程定义好两层间的接口规范让双方遵循这个规范来对接。OSI七层模型, 既复杂又不实用所以 OSI 七层模型没有落地、实现. 实际组建网络时是以TCP/IP 五层或四层模型来实现TCP/IP五层(或四层)模型:应用层负责应用程序间沟通, 我们的网络编程主要就是针对应用层传输层负责两台主机之间的数据传输。如传输控制协议 (TCP)能够确保数据可靠的从源主机发送到目标主机。网络层负责地址管理和路由选择。路由器工作在网路层数据链路层: 负责设备之间的数据帧的传送和识别, 交换机工作在数据链路层物理层负责光/电信号的传递方式. 集线器工作在物理层物理层我们考虑的比较少。因此很多时候也可以称为 TCP/IP四层模型封装和分用:应用层数据通过协议栈发到网络上时每层协议都要加上一个数据首部(header)称为封装. 首部信息中包含了一些类似于首部有多长载荷(payload)有多长上层协议是什么等信息. 数据封装成帧后发到传输介质上到达目的主机后每层协议再剥掉相应的首部根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理2. 传输层重点协议应用层重点协议HTTP及HTTPS, 我会单独写一篇介绍.网络层和数据链路层不做介绍.传输层重点协议负责数据能够从发送端传输接收端。2.1 TCP协议TCP(Transmission Control Protocol)传输控制协议。人如其名要对数据的传输进行一个详细的控制。TCP协议格式: 源端口、目标端口、序列号、确认号、标志位, 窗口大小, 校验和, 紧急指针TCP对数据传输提供的管控机制主要体现在两个方面安全和效率. 保证数据传输安全的前提下尽可能的提高传输效率2.1.1 确认应答, 超时重传(安全机制)确认应答: TCP将每个字节的数据都进行了编号。即为序列号, 每一个ACK都带有对应的确认序列号意思是告诉发送者我已经收到了哪些数据下一次你从哪里开始发超时重传机制: 主机A发送数据给B之后可能因为网络拥堵等原因数据无法到达主机B, 如果主机A在一个特定时间间隔内没有收到B发来的确认应答就会进行重发但是主机A未收到B发来的确认应答也可能是因为ACK丢失了, 因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包并且把重复的丢弃掉, 这时候我们可以利用前面提到的序列号就可以很容易做到去重的效果2.1.2 连接管理(安全机制)在正常情况下TCP要经过三次握手建立连接四次挥手断开连接三次握手:第一次握手客户端 - 服务器 客户端发送一个 SYN 包 包里的 序列号Seq 一个随机值第二次握手服务器 - 客户端服务器收到后回复一个 SYN ACK 包 包里的 确认号Ack x 1包里的 序列号Seq 服务器的随机值比如 y第三次握手客户端 - 服务器 客户端收到后再发一个 ACK 包。 包里的 确认号Ack y 1为什么不是 2 次因为如果只有两次服务器发出“听到了”之后并不知道客户端有没有收到它的回复。为什么不是 4 次因为第二次握手的 SYN请求和 ACK确认完全可以在同一个网络包里发送它们不冲突。合在一起就是3次分开就是4次3次是效率最高的最优解。四次挥手:第一次挥手主动方 - 被动方: 主动方发送一个 FIN 包第二次挥手被动方 - 主动方: 被动方回复一个 ACK 包此时被动方知道自己要关闭了但数据可能还没发完第三次挥手被动方 - 主动方):被动方把剩下的数据发完然后发送一个 FIN 包第四次挥手主动方 - 被动方: 主动方收到FIN后回复一个 ACK 包主动方此时进入 TIME_WAIT 状态等待 2MSL最长报文段寿命约 60 秒 后才真正关闭。为什么要有 TIME_WAIT 状态MSL是TCP报文的最大生存时间因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失否则服务器立刻重启可能会收到来自上一个进程的迟到的数据但是这种数据很可能是错误的同时也是在理论上保证最后一个报文可靠到达, 假设第四次挥手主动方发的ACK在网络中丢失了被动方会等不到ACK以为自己发出的FIN没被收到于是会超时重传这个FIN。主动方必须处于 TIME_WAIT 状态才能收到这个重传的FIN并再次回复ACK. 如果主动方发完ACK直接关闭万一这个ACK丢了被动方重传FIN时主动方已经关掉了系统会返回 RST 包重置连接导致被动方报错2.1.4 滑动窗口(效率机制)刚才我们讨论了确认应答策略对每一个发送的数据段都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点就是性能较差。尤其是数据往返的时间较长的时候.既然这样一发一收的方式性能较低那么我们一次发送多条数据就可以大大的提高性能其实是将多个段的等待时间重叠在一起了窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000个字节四个段。发送前四个段的时候不需要等待任何ACK直接发送收到第一个ACK后滑动窗口向后移动继续发送第五个段的数据依次类推操作系统内核为了维护这个滑动窗口需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答只有确认应答过的数据才能从缓冲区删掉窗口越大则网络的吞吐率就越高那么如果出现了丢包如何进行重传情况一: 数据包已经抵达ACK被丢了。这种情况下部分ACK丢了并不要紧因为可以通过后续的ACK进行确认情况二: 数据包就直接丢了。假如是数据包1001 - 2000丢包了当某一段报文段丢失之后发送端会一直收到 1001 这样的ACK就像是在提醒发送端 “我想要的是 1001” 一样如果发送端主机连续三次收到了同样一个 “1001” 这样的应答就会将对应的数据 1001 - 2000 重新发送这个时候接收端收到了 1001 之后再次返回的ACK就是7001了因为2001 - 7000接收端其实之前就已经收到了被放到了接收端操作系统内核的接收缓冲区中. 这种机制被称为 “高速重发控制”2.1.5 流量控制, 拥塞控制(效率机制)接收端处理数据的速度是有限的。如果发送端发的太快导致接收端的缓冲区被打满这个时候如果发送端继续发送就会造成丢包继而引起丢包重传等等一系列连锁反应流量控制: 因此TCP支持根据接收端的处理能力来决定发送端的发送速度。这个机制就叫做流量控制FlowControl接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段通过ACK端通知发送端窗口大小字段越大说明网络的吞吐量越高接收端一旦发现自己的缓冲区快满了就会将窗口大小设置成一个更小的值通知给发送端发送端接受到这个窗口之后就会减慢自己的发送速度. 如果接收端缓冲区满了就会将窗口置为0这时发送方不再发送数据但是需要定期发送一个窗口探测数据段使接收端把窗口大小告诉发送端虽然TCP有了滑动窗口这个大杀器能够高效可靠的发送大量的数据。但是如果在刚开始阶段就发送大量的数据仍然可能引发问题。 因为网络上有很多的计算机可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下贸然发送大量的数据是很有可能引起雪上加霜的. TCP引入 慢启动 机制先发少量的数据探探路摸清当前的网络拥堵状态再决定按照多大的速度传输数据拥塞控制: 发送开始的时候定义拥塞窗口大小为1, 每次收到一个ACK应答拥塞窗口加1, 每次发送数据包的时候将拥塞窗口和接收端主机反馈的窗口大小做比较取较小的值作为实际发送的窗口.像上面这样的拥塞窗口增长速度是指数级别的。“慢启动” 只是指初使时慢但是增长速度非常快. 为了不增长的那么快因此不能使拥塞窗口单纯的加倍。此处引入一个叫做慢启动的阈值, 当拥塞窗口超过这个阈值的时候不再按照指数方式增长而是按照线性方式增长.当TCP开始启动的时候慢启动阈值等于窗口最大值, 在每次超时重发的时候慢启动阈值会变成发生拥塞时的窗口大小的一半同时拥塞窗口置回12.1.6 延迟应答, 捎带应答(效率机制)延迟应答如果接收数据的主机立刻返回ACK应答这时候返回的窗口可能比较小。窗口越大网络吞吐量就越大传输效率就越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率假设接收端缓冲区为1M。一次收到了500K的数据如果立刻应答返回的窗口就是500K。 在这种情况下接收端处理还远没有达到自己的极限即使窗口再放大一些也能处理过来 如果接收端稍微等一会再应答比如等待200ms再应答那么这个时候返回的窗口大小就是1M并不是所有包都可以延迟应答 会有数量限制每隔N个包就应答一次时间限制超过最大延迟时间就应答一次。具体的数量和超时时间依操作系统不同也有差异捎带应答把确认信息ACK搭便车塞进正要发出去的数据包里省得单独为确认信息发一个空包2.1.7 粘包问题在TCP的协议头中没有如同UDP一样的 “报文长度” 这样的字段但是有一个序号这样的字段, TCP 有粘包问题因为它是面向字节流的, 没有消息边界.站在传输层的角度TCP是一个一个报文过来的。按照序号排好序放在缓冲区中。站在应用层的角度看到的只是一串连续的字节数据。那么应用程序看到了这么一连串的字节数据就不知道从哪个部分开始到哪个部分是一个完整的应用层数据包。那如何避免粘包问题呢----明确两个包之间的边界。对于定长的包保证每次都按固定大小读取即可对于变长的包可以在包头的位置约定一个包总长度的字段从而就知道了包的结束位置对于变长的包还可以在包和包之间使用明确的分隔符应用层协议是程序员自己来定的只要保证分隔符不和正文冲突即可对于UDP协议来说是否也存在 “粘包问题” 呢UDP 没有粘包问题因为它是面向数据报的, 就有很明确的数据边界, 站在应用层的角度使用UDP的时候要么收到完整的UDP报文要么不收。不会出现半个的情况2.2 UDP协议UDP协议格式: 源端口号, 目的端口号, UDP长度, 校验和UDP传输的过程类似于寄信:无连接: 知道对端的IP和端口号就直接进行传输不需要建立连接不可靠: 没有任何安全机制发送端发送数据报以后如果因为网络故障该段无法发到对方UDP协议层也不会给应用层返回任何错误信息.面向数据报: 应用层交给UDP多长的报文UDP原样发送既不会拆分也不会合并如果发送端一次发送100个字节那么接收端也必须一次接收100个字节而不能循环接收10次每次接收10个字节大小受限: UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K包含UDP首部). UDP协议理论上能装下 64KB 数据但网络设备只允许它舒舒服服地一次性传送1.4KB2.3 TCP/UDP对比TCP用于可靠传输的情况应用于文件传输重要状态更新等场景;UDP用于对高速传输和实时性要求较高的通信领域例如早期的QQ视频传输等。另外UDP可以用于广播我之前认为UDP用的比较少了, 一了解才发现, UDP不仅现在还在用而且用得极多:视频/直播抖音、腾讯会议、Zoom视频流一秒发几十帧偶尔丢一帧画面花一下没关系但绝对不能等重传实时游戏英雄联盟、吃鸡、FPS射击你的每一次走位、开枪必须毫秒级送达服务器。TCP的“确认-重传”机制在这种场景下是致命的宁可丢包让敌人瞬移也不能等TCP重传导致人物漂移.内部微服务, DNS域名解析等等