主机开通成功网站建设中,油田公司健康企业建设,网络运营岗位职责,网站项目建设所需成本✏️作者#xff1a;银河罐头 #x1f4cb;系列专栏#xff1a;JavaEE #x1f332;“种一棵树最好的时间是十年前#xff0c;其次是现在” 目录TCP/IP协议应用层协议自定义应用层协议DNS传输层协议端口号UDP协议UDP协议端格式TCP协议TCP协议段格式TCP工作机制确认应答(安… ✏️作者银河罐头 系列专栏JavaEE “种一棵树最好的时间是十年前其次是现在” 目录TCP/IP协议应用层协议自定义应用层协议DNS传输层协议端口号UDP协议UDP协议端格式TCP协议TCP协议段格式TCP工作机制确认应答(安全机制)超时重传(安全机制)连接管理(安全机制)滑动窗口(效率机制)流量控制(安全机制)拥塞控制(安全机制)延时应答(效率机制)捎带应答(效率机制)面向字节流异常情况UDP 和 TCP 对比网络层协议IP协议地址管理路由选择数据链路层协议以太网以太网帧格式MTUTCP/IP协议
应用层协议
自定义应用层协议
为啥要自定义协议
当前的应用程序要解决的业务场景是错综复杂的不同的公司有不同的业务不同的业务有不同的流程业务复杂要用程序来解决这个复杂的业务程序也就复杂了。因此很难有一个通用的协议满足所有的业务需求。
怎样进行自定义协议
1)结合需求分析清楚请求响应(客户端服务器之间)要传递哪些信息
2)明确传递的信息是以什么样的格式来组织
可选的方案是很多的。
约定好协议得格式内容之后客户端就能够按照这个格式构造数据并发送服务器按照这个格式解析处理。
约定的协议的内容(传递的信息)是和业务相关性非常大的。但是协议的数据组织的格式(传递的格式)和业务关系不大.
典型的用来组织数据的格式
XML 标签化的数据组织格式。使用标签来表示键值对以及树形结构 开始标签和结束标签需要成对出现标签中间的部分就是标签的内容内容可以是数字字符串还可以嵌套放别的标签。
HTML 是 XML 的特殊情况
XML中标签名字叫啥都是自定义的
json 上述 xml 和 json 都是按照文本的方式来组织的
优点是可读性好用户不需要借助其他工具肉眼能看懂。
缺点是效率不高占用较多的网络带宽。
xml 要额外传很多标签json 要额外传很多的key
protobuffer (谷歌)
二进制的表示数据的方式针对上述的数据信息通过二进制的形式进行压缩表示了。
特点是肉眼观察不了(二进制直接用记事本打开乱码)但是占用空间小了占用的带宽也就降低了。
DNS
域名解析系统 域名网址。 egwww.baidu.com 要访问网络上的服务器需要 IP 地址。IP地址不好记于是就使用一些简单的字符串来表示这个地址。
每个域名都对应了 1/N 个IP 地址。 最原始的做法是使用一个 hosts 文件 C:\Windows\System32\drivers\etc 像 hash 表一样建立了 IP 和域名之间的映射关系当然现在打开 hosts 文件基本都是空的 # 表示注释 当访问某个域名的时候就自动请求下 DNS 服务器DNS 就会进行查询将得到的结果(具体的 IP 地址)返回给你。
如果你电脑的 DNS 服务器配置的不对或者 DNS 服务器挂了此时就会出现一个典型的现象QQ 能用但是网页打不开。
当前要求网站的域名不能重复(保证唯一)。
全世界这么多网站如何保证唯一呢
一级域名二级域名三级域名… pic.sogou.com .com(公司) 一级域名类似的一级域名还有 orgcnus… sogou 二级域名表示 搜狗这个公司 pic 三级域名 域名分级了DNS 服务器也是分级了有 一级域名 的 DNS 服务器还有 二级域名三级域名…
一般常见的就是 三级四级左右。 www. 具体 www 算 三级还是 四级还是 五级看域名具体咋写的 www 是万维网的缩写我们现在使用的这个网络就是 万维网 传输层协议
端口号
端口号数据库 mysql 默认端口 3306。
端口号起到的效果就是区分一个主机上的具体的应用程序。
所以同一台主机上一个端口号不能被多个进程绑定。 使用 IP 地址来区分主机。 eg 进程 A 绑定了 3306此时进程 B 也尝试绑定 3306进程 B 绑定操作就会失败 (抛异常) 端口号是传输层协议的概念TCP 和 UDP 协议的报头中都会包含 源端口 和 目的端口。
TCP 和 UDP 都是用 2 个字节16 个 bit 位来表示端口号的一个端口号的取值范围0 ~ 65535 最初学习 C 语言就得知道不同长度字节数表示的数据范围。 1 个字节8 bit , -128 ~ 127 128 就是 2 ^ 7, 127 就是 2 ^ 7 - 1 0 ~ 255 255 就是 2 ^ 8 - 1 2 个字节 , 16 bit, -32768 ~ 32767 32768 就是 2 ^ 15 0 ~ 65535 65535 就是 2 ^ 16 - 1 4 个字节32 bit -21亿 ~ 21亿 0 ~ 42 亿 9 千万 但是自己写程序绑定的端口号得是从1024 起的。
0 ~ 1023 这个范围的端口称为知名端口号/具名端口号这些端口号已经分配给了一些知名的广泛使用的应用程序了。 那么我写代码就非要指定 0 ~ 1023 的端口号行不行呢 ? 1.先确定你这个端口号没有被别的程序绑定 2.你有管理员权限 1023 以下的端口也不是完全不能用只是不建议这些端口虽然被分配给了特定程序但是这个程序是否在你电脑上运行着电脑上是否安装了这些程序都是不一定的。 UDP协议
UDP 的特点无连接不可靠传输面向数据报全双工。
不可靠传输没有任何安全机制发送端发送数据报以后如果因为网络故障该段无法发到对方UDP协议层也不会 给应用层返回任何错误信息。
UDP协议端格式 UDP 协议报文结构这张图任何一个计算机网络的教科书上都有而且都是这么画的但是实际上这么画不够严谨(为了书排版方便变形了) UDP 就会把载荷数据(就是通过 UDP socket 也就是 send 方法拿来的数据)再在前面拼装上几个字节的报头,相当于字符串拼接(此处是二进制的不是文本的)
UDP 报头里包含了一些特定的属性携带了一些重要的信息。不同的协议功能不同报头中的属性信息不同。
对于 UDP 来说报头 一共 8 个字节分成 4 个部分(每部分 2 字节)
UDP 报文长度
这个长度也是用 2 个字节表示的2 个字节表示的范围是 0 ~ 65535(64 KB).
也就是说一个 UDP 数据报只能传输 64 KB 的数据。 报文长度是整个报文的长度不是载荷长度。 如果 应用层数据报超过 64 KB 怎么办 方案 1: 就需要在应用层通过代码的方式针对应用层数据报进行手动的分包拆成多个包通过多个 UDP 数据报进行传输(本来是 send 一次现在需要 send 多次了) 方案2不用 UDP 了换成 TCP(TCP 没有这样的限制) 校验和
作用是验证传输的数据是否是正确的。
网络传输本质上就是光信号/电信号这些可能会受到一些物理环境的影响(电场/磁场/高能射线)在这些干扰下可能会出现比特翻转的情况。(1-00-1)
一旦数据变了对于数据的含义可能是致命的。
这种现象是客观存在的不可避免我们要做的就是及时识别出当前数据是否出现问题。
校验和是针对数据内容进行一系列数学运算得到一个比较短的结果(2 个字节)。
如果数据内容一定校验和结果就一定如果数据变了得到的校验和结果就变了。 是否有这样的情况假设数据传输中出错了但是计算的 校验和 和之前的 校验和 恰好一样 “要发射导弹” 0xaabb “不要发射导弹” 0xaabb 这个情况理论上存在工程上出现这种情况的概率极小忽略不计了。
如果内容相同得到的校验和一定相同
如果校验和相同内容不一定相同(小概率事件)
实际网络传输过程中往往是把数据的所有字节都参与生成校验和的运算这样任何一个字节出问题就都能发现了。
针对网络传输的数据来说生成校验和的算法有很多种。其中比较知名的有几个。
CRC
循环冗余校验把数据的每个字节循环往上累加如果累加溢出了高位就不要了。
好酸但是校验结果不理想如果数据同时变动了 2 个 bit 位前一个字节少 1 后一个字节 多 1 这种就会出现内容变了但是校验和没变这种情况。
MD5
MD5 不是简单的相加有一系列公式来进行更加复杂的数学运算。
MD5算法的特点
1)定长无论原始数据多长得到的 MD5都是固定长度(4/8字节)
2)冲突概率很小原始数据哪怕只变动一个地方算出的 MD5 都会差别很大(让 MD5 值更分散了)
3)不可逆通过原始数据计算 MD5 很容易通过 MD5 还原成原始数据很难理论上是不可实现的(计算极大)
MD5 的这些特点使得 MD5 作用更多了校验和作为计算 hash 值的方式加密
SHA1
SHA1的特点和 MD5 相同区别是计算方式不同。
TCP协议
特点是有连接可靠传输面向字节流全双工。
这里的可靠传输是 TCP 的内部机制和编码关系不大。
TCP协议段格式 4位首部长度
TCP 报文 TCP 报头(首部) header TCP 载荷 payload/body
一个TCP 报头长度是可变的不是像 UDP 报头固定是 8 个字节
选项
option (选项) optional (可选的可有可无的)
此处的选项是对 TCP 报文的一些属性进行解释说明的。
首部长度描述了 TCP 报头有多长选项之前的长度是固定的(20 字节)首部长度 - 20 选项长度
首部长度的单位是 4 字节
如果首部长度值是 5表示整个 TCP 报头长度是 20 字节没有选项
如果首部长度值是 15 表示整个 TCP 报头长度是 60 字节选项长度是 40 字节
保留( 6 位)
reserved
C 语言中有一类单词叫做关键字除了关键字之外还有一些单词叫做保留字。 保留字就是现在还没使用但是保不齐以后要是用所以现在这占个位置你现在先别用 咱们进行程序开发的时候其中一个重点考虑的事情就是可扩展性有些功能可能暂时不需要保不齐未来需要 16 位检验和
和 UDP 校验和同理
TCP工作机制
TCP 是一个复杂的协议里面有很多机制这里主要讨论 TCP 提供的 10 个比较核心的机制。
确认应答(安全机制)
TCP 是可靠传输。
可靠不是说发送方 100% 能把消息发给接收方而是尽可能把数据传过去发送方能知道自己的消息是发过去了还是丢了。
确认应答是实现可靠传输的最核心机制。 举个栗子 张三在追一个女生有一天张三给女生发消息说我请你吃饭好嘛“女生回复他说好啊”。 当张三收到好啊的时候说明张三发的消息已经顺利被女生看到了(没有丢包) 如果过了好久张三没收到女生的回应说明丢包了(也可能是已读不回doge) 这里女生回复的好啊就称为应答报文也叫作 ack(acknowledge) TCP 进行可靠性传输最主要考的就是这个确认应答机制。
A 给 B 发了个消息B 收到之后就会返回一个 应答报文(ACK)此时 A 收到应答之后就知道刚才发的数据已经顺利到达 B 了。
考虑更复杂的情况(发送方发多条消息) 张三可能连续发 2 条消息张三没等第 1 条消息的回应就发了第 2 条消息。
网络上可能存在后发先至的情况这个情况下收到消息的顺序可能是有变数的。 由于后发先至张三先收到了滚后收到了好啊。
很明显这里应答错乱导致出现歧义。
网络中数据的先发后至两个主机之间路线存在多条数据报1和数据报2走的都是不同的路线数据报1的转发路径上的交换机/路由器和数据报2也不一样有的转发速率快有的转发速率慢此时这2 个数据报的到达顺序可能会有变数。
网络中的后发先至是客观存在的因此应答报文到达的顺序也是存在变数的此时就需要考虑如何规避这种顺序错乱带来的歧义。
解决办法是给传输的数据和应答报文都进行编号。 “后发先至” eg: 结婚时候新郎的车队可能会后发先至 32位序号/确认序号 引入序号之后就不怕顺序错乱了即使顺序上乱了也可以通过序号来区分当前应答报文是针对哪个数据进行的。
任何一条数据(包括应答报文)都是有序号的确认序号则是只有应答报文有(普通报文确认序号里的值无意义)。
报文是否是应答报文取决于6个标志位中的 ACK如果 ACK 这个标志位为 1 表示是应答报文如果为 0 表示不是应答报文。 应答报文的序号仅仅是一个身份标识不需要应答 应答报文要是应答 应答报文就无限套娃了… TCP 的序号是按照字节来编写的。 这一条数据是 1000 个字节假设是从 1 开始编号此时第一个字节序号就是 1第 2 个字节序号就是 2…但是由于这 1000 个字节都属于同一个 TCP 报文TCP 报头里就只记录当前的第1 个字节的序号此处报头的序号写的是 1。接下来发第 2 条数据此时第 2 个TCP 数据报的第 1 个字节序号是 1001如果长度是 1000此时最后一个字节序号是 2000这1001~2000都属于一个 TCP 数据报那么这个TCP 数据报报头的序号就是 1001。
TCP 的字节的序号是依次累加的这个依次累加的过程对于后一条数据的第 1 个字节序号就是上一条数据的最后一个字节序号再加 1 。每个 TCP 数据报报头只需要填写 TCP 数据 第 1 个字节的序号即可。
TCP 知道了第 1 个字节的序号再结合报文的长度就可以知道每个字节的序号。
确认序号的取值是收到的数据的最后一个字节 1。
如上图确认序号写的是 1001就是在 1000的基础上 1。
表示的含义 1001的数据都已经确认收到了。主机 A 接下来应该从 1001 这个序号开始继续发送
总结TCP 的可靠传输最主要就是通过确认应答来保证的通过应答报文就可以让发送方清楚地知道传输是否成功进一步引入了序号和确认序号针对多组数据进行区分。
超时重传(安全机制)
前面讨论确认应答只是讨论了顺利传输的情况。如果丢包了呢
丢包涉及 2 种情况
1.发的数据丢了
2.返回的 ack 丢了 发送方看到的结果就是没有收到 ack 不能区分是哪一种情况。
丢包是一个概率性事件通常情况下丢包的概率是很小的因此如果重新发一遍这个数据还是有很大可能传输成功的。
因此 TCP 就引入了 重传机制。
在丢包的时候重新传一遍数据。
到底这次传输是丢包了还是 ack 传的慢
TCP 就引入了时间阈值。
发送方发出数据后就会等待 ACK此时开始计时。只要超过了这个时间不管是丢包了还是 ack 在路上都视为是丢包了。 比如寒假作业没带等于没写虽然你写了你超过了这个规定提交时间就当做没写处理。 超时重传超过一定时间还没响应就重新传输。
这个超时时间具体是多少 ms 因为这个时间是可配置的不同系统上的默认值可能都存在差别。
如果是 ack 丢了这种情况
对于主机 B 来说1~1000 就收到了 2 次如果你发的这个数据是一个支付请求(寄了)
TCP 对于这种重复数据的传输是有去重处理的
TCP 存在一个接收缓冲区这样的存储空间(接收方操作系统内核里的一段内存)
每个 TCP socket 对象都有一个接收缓冲区(其实也有一个发送缓冲区)
主机 B 收到主机 A 的数据
其实是 B 的网卡读到数据了然后把这个数据放到 B 的对应 socket 的接收缓冲区(想象成阻塞队列)后续应用程序使用 getInputStream进一步使用 read从接收缓冲区里读数据。
在接收缓冲区里根据数据的序号TCP 很容易识别当前接收缓冲区里的这 2 条数据是否是重复的如果重复就把后来的数据丢弃保证 应用程序调用 read 读到的数据一定是不重复的。 去重可以理解为是一个优先级队列有序队列。 前面说了网络上传输的数据可能后发先至, TCP 利用这个接收缓冲区对收到的数据重新进行排序是应用程序 read 的数据都是有序的(保证和发送顺序一致 根据序号排序序号相同就去重 eg结婚当天新郎的车队出现后发先至然后车队都到了新娘家门口的时候要整队排序 这时候我们可以利用前面提到的序列号就可以很容易做到去重的效果。
总结由于去重和重新排序机制的存在发送方只要发现 ACK 没有及时到达就会重传数据即使重复了即使数据乱了接收方都能去重和排序(依赖 TCP 报头的序号)。
重传的数据是否可能又丢包了呢
有可能超时重传可能传多次如果重传好几次都没传过去此时再重传意义不大了。
从数学角度来理解
假设一次传输丢包概率是 10%传输成功概率是 90%
如果第1次传输丢包第 2 次传输也丢包了概率是 10% * 10% 1%
如果 3 次都丢了概率是 0.1% 连续重传都丢包此时的概率原则上讲是非常低的如果这个情况真的出现了只能说明此时丢包概率远远不止 10% 你当前网络出现重大故障 因此重传达到一定次数时就不会继续重传会认为网络出现故障。
接下来 TCP 会尝试 重置连接(相当于断开重连)如果重置还是失败就彻底断开连接了。 具体重传几次 N也是可配置的不去研究 重传的时候第 1 次重传和第 2 次重传超时时间间隔不一样。一般来说重传轮次越大超时时间间隔就越大。超时时间越大重传频率就越低。(因为重传次数越多说明重传成功概率越低此时你重传的太快也是白浪费系统资源)
总结可靠传输是 TCP 最核心的部分TCP 的可靠传输就是通过 确认应答 超时重传来体现的。其中确认应答描述的是传输顺利的情况而超时重传描述的传输出现问题的情况。
连接管理(安全机制) 什么是断开连接
A 和 B 把自己存储的连接信息(数据结构)删除了连接就断开了。 JDBC 是基于 TCP 建立的连接 连接(Connection) 链接(Link) 快捷方式比如电脑开始菜单的图标就是快捷方式比如我想打开 QQQQ本来是 在 C 盘某个目录里我每次打开 QQ 都要到这个目录去找未免太麻烦所以就创建一个快捷方式这个快捷方式就是一个文件这个文件里保存了这个可执行文件的真实路径 管理
就是描述了连接如何创建如何断开。
TCP 三次握手和四次挥手
滑动窗口(效率机制)
确认应答超时重传连接管理都是给 TCP 可靠性提供的支持。
引入了可靠性也付出了相应的代价(传输效率)
可靠性和效率是冲突的。
因此 UDP 虽然没有 可靠性但是传输效率比 TCP 高
所以 TCP 在竭尽可能的提高传输效率(本质上是补救措施)。再怎么提高也不可能比 UDP 这种不考虑可靠性的效率高。
滑动窗口本质上是降低了确认应答等待 ACK 消耗的时间。 在进行 IO 操作的时候其实时间成本主要是 2 个部分 1.等 2.数据传输(数据拷贝) 大多数情况下IO 操作消耗的时间大部分在等上面 举个栗子 放寒假从学校回家如果两地比较远坐飞机回家的情况下。 真正坐飞机的时间很短但是因为机场一般离市区很远从学校到机场要花时间到了机场后换登机牌、托运行李、安检、候机又要花上不少时间飞机到达目的地取行李从机场到家里又要花上不少时间。 这里真正坐飞机的时间就相当于 数据传输的时间较短。 而其他花在路上的时间等待时间比较长。 具体怎么缩短 批量发送批量等待把多份等待时间合并成一份。 滑动窗口的本质就是不等待的批量发送一组数据然后使用一份等待时间来等待一组数据的多个 ack。 举个例子 我打算去买肉夹馍炒饭烤肠。 方案一先去买肉夹馍肉夹馍做好了再去买炒饭炒饭做好了再去买烤肠。 方案二先去买肉夹馍不等了立即去买炒饭也不等立即去买烤肠。 方案一就是用了 3 份等待时间而方案二只用了 1 份等待时间 把不需要等待就能直接发送数据的最大的量叫做窗口大小。上面第 2张图里窗口大小就是 4000。
当批量发送了 窗口大小的这些数据之后发送方就要等待 ack 了。
啥时候往下发送等待啥时候结束
不是说等所有的 ack 都到达才往下发而是收到一条 ack 就往下发 1 条。(这样就让我们等待的 ack 始终都是 4 条) 在上述情况下如果丢包了咋办
ack 丢了 上述丢包重传的机制叫做 “快速重传”(重传操作只重传了丢失的数据)
这个可以视为是 超时重传 机制在滑动窗口下的变形。
如果当前传输数据密集按照滑动窗口的方式传输此时就按照快速重传来处理丢包
如果当前传输数据稀疏不再按照滑动窗口的方式传输此时就按照之前的超时重传来处理丢包。
流量控制(安全机制)
是一种干预发送的窗口大小的机制。
滑动窗口窗口越大传输效率越高(一份时间等的 ack 越多)。 但是窗口也不能无限大 1.完全不等 ack 可靠性难以保证 2.窗口太大也会消耗大量的系统资源 3.发送速度太快接收方接收不过来发了也白发接收缓冲区有上限。 接收方的处理能力是一个重要的约束依据。发送方发的速度不能超过接收方的处理能力。
流量控制就是根据接收方的处理能力来协调发送方的发送速率。
如何衡量接收方的处理能力 一个量化的方法计算接收方一秒钟能处理多少个字节…(这种方式实现起来有些困难) 更简单的办法 直接看接收方接收缓冲区里剩余空间的大小。
每次 A 给 B 发了个数据B 就需要算一下缓存区里剩余空间然后把这个值通过 ack 报文返回给 A。
A 就根据这个值来决定接下来发送的速率是多少(窗口大小是多少) 窗口大小 16 位是否意味着窗口大小最大是 16 kb
不是
TCP 为了让窗口更大在选项部分引入了窗口扩展因子。
比如窗口大小已经是 64 kb扩展因子里写了个 2 意思就是让 64 kb 2 256kb
由于接收方缓存区剩余空间是一直在动态变化的所以每次返回 ack 带的窗口大小都在变化发送方也要进行动态调整。 当窗口大小为0发送方就要暂停发送。暂停发送的等待过程中会给 B 定期发送窗口探测报文这个报文不携带具体的业务数据只是为了触发 ack 查询窗口大小。
拥塞控制(安全机制)
流量控制和拥塞控制共同决定发送方的窗口大小是多少。
流量控制考虑的是接收方的处理能力。
拥塞控制描述的是传输过程中中间节点的处理能力。 木桶效应一只水桶能装多少水取决于它最短的那块木板。 接收方的处理能力好量化衡量。但是中间节点不好衡量。 设计 TCP 的大佬们想出了一个相当 天才的办法 既然不好直接量化那么可以通过实验的方式来测试出一个合适的量 拥塞窗口不是固定数值而是一直动态变化的。随着时间的推移逐渐到达一个动态平衡的过程。
这样既能够把问题解决同时也能随着网络的动态变化而动态变化。
拥塞窗口和流量控制窗口共同决定了发送方实际的发送窗口。(取拥塞窗口和流量控制窗口的较小值)
延时应答(效率机制)
就是在 滑动窗口的基础上做点别的操作。
收到数据之后不是立即返回 ack 而是稍微等会再返回。等待的时间里接收方的应用程序就能把接收缓存区的数据给消费一些此时剩余的空间就更大了。 实际上延时应答采取的方式就是在滑动窗口下ack 不再每一条数据都返回了比如上图是隔一条返回一个 ack。
实际上剩余空间大小既取决于发送方的发送也取决于接收方的处理。
捎带应答(效率机制)
也是提高效率的一种方式。
在延时应答的基础之上引入的捎带应答。
服务器客户端程序最典型的模型就是“一问一答”。业务的请求和响应。 本来是不同时机在延时应答下可能成为相同时机就合并了。 而 TCP 的三次握手本身是相同时机一定会合并此处是有一定概率合并此处和四次挥手的合并更像。 延时应答提高了合并的概率。 面向字节流
面向字节流引入了一件麻烦事
粘包问题。 举个栗子 接收缓冲区是把刚才收到的多个数据都放到一起了应用程序 read 读取的时候读到哪里才算是一个完整的应用层数据报呢?
由于 TCP 是面向字节流的可以一次读 1 个字节也可以一次读 N 个字节。
这就导致一次读取的时候可能读到的是半个应用层数据报也可能是 1 个应用层数据报还可能是多个应用层数据报。 应用程序调用 read
如果 read 的是 7 个字节此时正好读出的是 aaaaaaa这是一个完整的应用层数据报
如果 read 的是 8 个字节此时正好读出的是 aaaaaaab这是一个半的应用层数据报
如果 read 的是 6 个字节此时正好读出的是 aaaaaa这是半个应用层数据报。
在 TCP 层次没有在 socket api 中告诉我们要读几个字节具体怎么读都是人为操作。
期望读到的是整个的应用层数据报后续才好处理。
解决方案是 约定好应用层协议即可尤其是明确应用层数据报和应用层数据报之间的界限。
1.约定好分隔符
2.约定每个包的长度
二选一即可。
异常情况
传输过程中出现了不可抗力。
1.进程崩溃
2.主机关机(按照正常流程关机)
3.主机掉电
4.网线断开 1 和 2 是一类3 和 4 是一类。 1.进程崩溃进程没了对应的 PCB 没了对应的 文件描述符表就释放了相当于 socket.close()。此时内核会继续完成四次挥手此时仍然是一个正常断开的过程。
2.主机关机主机关机要先关闭进程然后才正式关机。(关闭进程的过程中也和上面一样触发四次挥手)
3.主机掉电显然是来不及挥手了。
假设是接收方掉电了。发送方仍然在传数据发完数据要等 ack , ack 等不到…超时重传再怎么重传还是收不到 ack。重传几次还没有应答尝试重置 TCP 连接(复位报文段…RST)。显然这个重置也会失败。放弃连接。(单方面放弃)
如果是发送方掉电。接收方发现没有数据了没数据是发送方挂了还是发送方在组织语言要稍等会再发接收方不知道先等。接收方需要周期性的给发送方发送一个消息(“心跳包”)确认下对方是否还工作正常。
心跳包(保活机制) 1.心跳是周期性的 2.心跳如果没了就是挂了。 心跳包是一个非常常见的机制分布式系统中还会涉及到心跳包 心跳包来确认通信双方是否工作正常。
4.网线断开发送方尝试重传接收方尝试发心跳包。 TCP 是个非常复杂的协议不仅仅是这 10 个特性这是 TCP 比较核心的特性。 了解 TCP 更多的特性应该去翻阅 RFC 文档翻阅操作系统内核源码 RFC 9293: Transmission Control Protocol (TCP) (ietf.org) UDP 和 TCP 对比
TCP 的优势在于可靠传输绝大部分场景中都需要可靠传输。
UDP 优势在于更高效率如果某些场景对于性能要求更苛刻。 同一个机房内部服务器之间通信。网络结构相对简单网络带宽比较充裕转发设备也是比较好的设备。整体丢包的可能性比较小。 UDP 还有一个优势天然支持广播。 IP 地址中有一种特殊的地址“广播 IP” 通过 UDP 往广播 IP 上发送数据此时该局域网内所有的设备都能够收到数据。 传输层的协议并非只有这 2 个。除了 TCP UDP 之外还有一些其他的传输层协议。有的传输层协议属于能够专门为游戏场景量身打造的(可靠性 效率) , 典型的协议以 KCP 为代表的一系列协议。
网络层协议
在复杂的网络环境中确定一个合适的路径。
1.地址管理 快递系统要想要建立起来就需要把世界上的地址能够以一定的规范定义出来。 2.路由选择 规划路径 网络层的代表IP协议。
IP协议
IP协议报头格式如下
IPv4协议(v4 版本的意思)
4 位版本
此处的取值只有 2 个。4 或 6。
IPv4IPv6
4 位首部长度
描述了 IP 报头多长(IP 报头是变长的)
此处的单位也是 4 字节。 IP 报头有一个选项部分是变长的是可有可无的。 8 位服务类型(TOS)
说是 8 位实际上只有 4 位有效这 4 位中只有 1 位可以是 1其他的都是 0。
4 位就表示 IP 协议的四种形态/4 种工作模式。
最小延时最大吞吐量最高可靠性最小成本。 最小延时包裹会最快速度送达。 最大吞吐量单位时间内你可以送更多的包裹。 最高可靠性包裹丢的概率是最小的。(和 TCP 的可靠性不是一个概念) 最小成本让运费最低。 实际开发中就可以根据需要来切换 IP 的模式来达到最优的效果。
16位总长度(字节数)
描述了一个 IP 数据报的长度。(头 载荷)
这个长度减去 IP 报头长度剩下的就是载荷长度就是一个完整的 TCP/UDP 数据报长度。
16 位总长度是否意味着一个 IP 数据报最多只能支持 64 KB
确实有这个限制但是 IP 自身就支持对 包的拆分和组装。 举个栗子 在淘宝上买了个床快递公司怎么运把床拆开以散件的形式发过来送到了家里有师傅上门组装。 一个 IP 数据报携带的数据载荷太大了超过了 64KB就会在网络层针对数据进行拆分把一个数据拆分成多个IP 数据报再分别发送接收方再重新组装。 比如发送方把 100KB 的数据交给传输层(封装)传输层交给网络层(封装)网络层就把这个 100KB 的数据拆包比如拆成两份 64KB 36KB。这两份再交给数据链路层由以太网分装成两个数据帧。接收方数据链路层针对两个数据帧进行分用得到两个 IP 数据包交给网络层网络层针对这俩 IP 数据包进行解析把里面的载荷拼成一个交给传输层 此处说是 64 KB实际上 IP 协议拆包不一定就按照64 KB为单位进行拆分实际的单位往往更小(取决于数据链路层的情况) 8位生存时间(TTL)
一个数据包在网络上能够传输的最大时间。
这个时间的单位不是秒而是次数
一个数据报构造出来会有一个初始的 TTL 数值(比如32或者64或者128)这个包每次经过一个路由器转发 TTL - 1如果一直减到 0 了还没有到达目标此时就认为这个报永远都到不了了就可以丢弃了。
8 位协议
描述了当前载荷部分内容是属于哪个协议的(TCP/UDP)
16 位首部检验和
此处只需要针对首部进行检验。
载荷部分(TCP/UDP数据报)自身已经有校验和了。 如果校验和不一致直接丢弃 32 位源 IP 地址 32 位目的 IP 地址
此处看到的 IP 地址是 32 位的整数
而日常见到的 IP 则是一串数字 eg111.183.72.219
点分十进制使用 3 个.把32位四个字节的数字给分隔开分成四个部分每个部分分别使用0 - 255 十进制整数表示。
地址期望每个设备都不相同但是32位数字只能表示42亿9千万个数字.
期望使用这个表示全世界上所有的上网设备。(智能手机PC服务器路由器其他杂七杂八的网络设备物联网)
为了解决IP地址不够用的问题想了很多办法。 动态分配IP地址此时就可以省下一批 IP 地址这个方案没有从根本上增加 IP 地址只是提高了利用率。 NAT 网络地址转换。本质是使用一个 IP 代表一批设备也能够大大提高 IP 地址的利用率。使用端口号区分。
在NAT的背景下就把 IP 地址分成两个大类
1)内网 IP (私有 IP) 10.* 172.16.* - 172.31.* 192.168.*
2)外网 IP (公网IP) 剩下的是公网 IP
NAT要求公网 IP 必须是唯一的。私网 IP 可以在不同的局域网中重复出现。
如果某个私网里的设备想访问公网设备就需要对应的 NAT 设备(路由器)把 IP 地址进行映射从而完成网络访问。
反之公网的设备无法直接访问私网的设备。不同局域网的私网的设备没法直接相互访问。 cmd - ipconfig 内网 IP 只要在局域网内部不重复即可不同局域网中则是允许重复的。
111.183.72.219 这是一个外网 IP
这些接入运营商路由器的电脑去访问外部服务器都会被路由器替换成路由器自己的外网 IP 。
此时只要这个电脑是经过运营商路由器转发给服务器服务器看到的源 IP 就都一样如果是多个电脑同时访问同一个服务器服务器的响应就会先发给路由器路由器根据这些电脑不同的端口号来区分决定发给哪个设备。
因此服务器能拿到的只是路由器的 IP 不能拿到我电脑的内网 IP 如果我电脑不主动和服务器联系服务器就不知道我的端口从而无法主动找到我。
NAT机制能够有效的解决 IP 不够用的问题但是带来的副作用就是网络环境更加复杂了。
IPv6 : 根本上解决了IP不够用的问题。
使用16字节表示IP地址128位。
16字节表示的地址的个数(42亿)^4
IPv6 虽然看起来非常好但是世界上仍然是以 NAT IPv4 动态分配来进行网络组建的真正使用 IPv6的地方非常非常少。
因为 IPv6 贵IPv6和IPv4不兼容如果你想要支持IPv6就需要更换路由器等网络设备花钱这个钱花的就没啥收益。因此大家都不愿意去升级。 IPv6 中国已经普及80%背后原因 地址管理
IP地址分为两个部分网络号和主机号。
网络号标识网段保证相互连接的两个网段具有不同的标识
主机号标识主机同一网段内主机之间具有相同的网络号但是必须有不同的主机号。 一个 IP 地址前面从哪儿到哪儿是网络号后面从哪儿到哪儿是主机号分界线是怎么定的
有一个单独的概念
子网掩码 网络号不一定就是前三个字节都是可以调整变化的。
此处的 255.255.255.0 就是子网掩码。
32位
1111 1111 1111 1111 1111 1111 0000 0000
左侧都是 1右侧都是 01的部分就描述了 IP 有多少位是网络号。
对于家用设备来说子网掩码最常见的就是 255.255.255.0 将IP地址中的主机地址全部设为0就成为了网络号代表这个局域网192.168.0.0 将IP地址中的主机地址全部设为1就成为了广播地址用于给同一个链路中相互连接的所有 主机发送数据包;(192.168.0.255 使用udp往这个地址上发数据报,整个局域网所有设备都能收到) 127.*的IP地址用于本机环回loop back测试通常是127.0.0.1 主机号为 1比如 192.168.0.1 通常是网关 IP(不绝对都可以配置) 将 IP 地址和子网掩码进行“按位与”操作二进制相同位与操作两个都是1结果为1否则为0得到的结果就是网络号。 将子网掩码二进制按位取反再与 IP 地址位与计算得到的就是主机号。
路由选择
路由选择就是规划路径。
相当于你使用地图导航一下由于网络环境非常复杂任何一个节点(路由器)都是无法感知到网络环境的全貌。一个路由器最多只认识它的一些邻居或者邻居的邻居进行一个比较长的路径的转发就比较麻烦需要一边走一边问。
路由选择核心思路是问路。每个路由器都会保存一定的周围设备的信息(路由表)每次有一个 IP 数据报经过路由器就需要匹配路由表看看接下来咋走如果路由表上有匹配的项(该路由器认识路)直接按照要求走就行了如果没有匹配的项路由器不认识路会提供一个默认路径大体方向是不会错的沿着这个方向继续走继续问。 每经过一个路由器问一次 TTL- 1如果减到零了还没到说明这个包就永远都到不了了这个地址没人知道了就被丢弃了。 六度空间理论你和任何一个陌生人之间所间隔的人不会超过六个也就是说最多通过6个中间人你就能够认识任何一个陌生人。 正常情况下像 32 这样的 TTL 足以让我们把数据报转发给世界上任何一个地址。 数据链路层协议
以太网
以太网帧格式 目的地址源地址
此处不是用 IP 地址 表示了而是用 mac 地址。 mac 地址 物理地址。这个是和 IP 地址完全独立的另外一套地址体系。 6 个字节(比 IPv4 地址大很多)当前每个设备都会有唯一的 mac 地址。不是动态分配的而是网卡出厂的时候就被设置好了的。 当前 IP 和 mac 是怎么相互配合的
IP 用来描述整个传输过程的起点终点mac 则是用来描述两个相邻结点的起点终点。
类型 ARP 协议
通过这个协议让某个 路由器/交换机 能够认识局域网里的其他设备。通过 ARP 协议会在 路由器/交换机 里建立出一个 表这个表相当于一个 hash 表能够建立出 IP 和 mac 之间的映射关系。
MTU
MTU 是数据链路层的一个数据帧能够承载数据的最大长度。(载荷长度) 载荷具体多长和使用的物理介质有很大关系也和数据链路层使用的协议有关系。比如以太网协议MTU 1500字节(这个和物理层有很大关系)
正是这个 MTU 引起了 IP 协议拆包组包IP 协议的分包组包通常不是根据 这个 IP 最大长度 64KB 来分的。大概率情况下MTU 比 64 KB 小。