概念
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。
作用
IP地址 是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
格式
IP地址 是一个 32位的二进制数,通常被分割为 4 个 “8位二进制数”(也就是4个字节),
通常用 “点分十进制” 的方式来表示,即 a.b.c.d 的形式(a,b,c,d都是0~255之间的十进制整数)。
组成
IP地址分为两个部分,网络号和主机号
- 网络号:标识网段,保证相互连接的两个网段具有不同的标识;
- 主机号:标识主机,同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号;
通过合理设置网络号和主机号,就可以保证在相互连接的网络中,每台主机的IP地址都是唯一的。
分类
分类 | 范围 | 适用网络 | 网络数量 | 主机最大连接数 |
---|---|---|---|---|
A类 | 0.0.0.0 ~ 127.255.255.255 | 大型网络 | 126 | 16777214 |
B类 | 128.0.0.0 ~ 191.255.255.255 | 中等规模网络 | 约16000个 65534 | ( 2 16 2^{16} 216-2) |
C类 | 192.0.0.0 ~ 223.255.255.255 | 小型网络 | - | 254( 2 8 2^8 28-2) |
D类 | 224.0.0.0 ~ 239.255.255.255 | - | - | - |
E类 | 240.0.0.0 ~ 247.255.255.255 | - | - | - |
备注:主机最大连接数减去2,是扣除主机号为全0和全1的特殊IP地址。
在上述的分类中,存在IP地址浪费的问题:
为了解决以上问题,引入子网掩码来进行子网划分:
格式
子网掩码格式和IP地址一样,也是一个32位的二进制数。其中左边是网络位,用二进制数字“1”表示,1 的数目等于网络位的长度;右边是主机位,用二进制数字“0”表示,0的数目等于主机位的长度。
子网掩码也可以使用二进制所有高位1相加的数值来表示。
作用
- 划分A,B,C三类 IP 地址子网: 如一个B类IP地址:191.100.0.0,按A ~ E类分类来说,网络号二进制数为16位网络号+16位主机号。 假设使用子网掩码
255.255.128.0(即17)来划分子网,意味着划分子网后,高17位都是网络位/网络 号,也就是将原来16位主机号,划分为1位子网号+15位主机号。
此时,IP地址组成为:网络号+子网号+主机号,网络号和子网号统一为网络标识(划分子网后的网络号/网段)- 网络通信时,子网掩码结合IP地址,可以计算获得网络号(划分子网后的网络号)及主机号(划
分子网后的主机号)。一般用于判断目的IP与本IP是否为同一个网段。
对于网络通信来说,发送数据报时,目的主机与发送端主机是否在同一个网段,流程是不一样 的。
计算方式
将 IP 地址和子网掩码进行“按位与”操作(二进制相同位,与操作,两个都是1结果为1,否则为0),得到的结果就是网络号。
将子网掩码二进制按位取反,再与 IP 地址位与计算,得到的就是主机号。
特殊的 IP 地址
- 192.168.0.1 / 192.168.1.1:主机号为 .1 的 IP,通常用来作为 “网关”。关:入口,出口。
- 192.168.0.0 / 192.168.1.0:主机号为 .0 的 IP,作为网络号(表示当前局域网 / 网段)。
- 192.168.0.255 / 192.168.1.255:主机号为 .255 的 IP,通常作为 广播 IP
- 127.0.0.1 / 127.* :环回 IP(表示主机自己)
MAC地址,即 Media Access Control Address,用于标识网络设备的硬件物理地址。
- MAC地址用来识别数据链路层中相连的节点;
- 长度为48位,及6个字节。一般用16进制数字加上冒号的形式来表示(例如:08:00:27:03:fb:19)
- 在网卡出厂时就确定了,不能修改。虚拟机中的MAC地址不是真实的MAC地址,可能会冲 突;也有些网卡支持用户配置MAC地址。
特殊的MAC地址
广播数据报:发送一个广播数据报,表示对同网段所有主机发送数据报。广播数据报的MAC地址为:
FF:FF:FF:FF:FF:FF
DNS,即Domain Name System,域名系统。DNS 是一整套从域名映射到IP的系统。
TCP/IP 中使用 IP 地址 来确定网络上的一台主机,但是 IP 地址 不方便记忆,且不能表达地址组织信息,于是人们发明了域名,并通过域名系统来映射域名和IP地址。
域名可以通过 DNS 系统自动转换成对应的 IP 地址。
最早的 DNS 系统,是一个文件,称为 hosts 文件。这个方式比较原始,现在基本上不用了。
现在的网站,成千上万,不能把所有的映射关系都写到文件中。
因此,更科学的方法,使用专门的 DNS 服务器,来保存这个文件。
使用服务器把这些映射关系都存储好,哪个电脑需要 DNS 解析,就访问这个 DNS 服务器即可。
但全世界要上网的设备,是非常多的,每个设备上网的时候,都要请求 DNS 服务器?DNS
服务器能扛得住这么大的访问量吗?显然是不能的,那么如何解决 DNS 服务器访问量太大的问题呢?
- 主机在请求 DNS 之后,会对映射关系在本地进行缓存,这样就可以大大的减少客户端访问 DNS 服务器请求的数量。(域名 => IP 这个映射关系,虽然会变,但是频率比较低)
- 在全世界,架设很多的 DNS 镜像服务器
- 最初的 DNS 服务器,称为 “根服务器”。
- 其他的 DNS 服务器,从根服务器上同步数据,称为 “镜像服务器”。
NAT:IP 地址转换
把 IP 地址分成两个大类:
- 内网 IP(局域网中使用的 IP)
- 外网 IP(广域网中使用的 IP)
允许局域网之间的内网 IP 重复,但是外网 IP 要保持唯一。
同一个局域网中的 IP 地址不能相同,但是不同局域网中的 IP 允许重复。
NAT 机制的本质就是用一个 外网 IP 代表一大批 内网的设备!
那么问题来了,如果局域网内,有多个主机都访问同一个外网服务器,那么对于服务器返回的数据中,目的IP都是相同的。那么NAT路由器如何判定将这个数据包转发给哪个局域网的主机?
这时候NAPT来解决这个问题了。使用IP+port来建立这个关联关系
这种关联关系也是由NAT路由器自动维护的。例如在TCP的情况下,建立连接时,就会生成这个表项;在断开连接后,就会删除这个表项
HTTP及HTTPS是应用层重点协议,我们会在Web开发中学习。
TCP,即Transmission Control Protocol,传输控制协议。人如其名,要对数据的传输进行一个详细的控制。
TCP对数据传输提供的管控机制,主要体现在两个方面:可靠和效率。
这些机制和多线程的设计原则类似:保证数据传输可靠的前提下,尽可能的提高传输效率。
- 一口气发了 1000 个字节的数据(一个 TCP 数据报,长度是 1000,序号是 1)
- 应答报文中的确认序号,就是 1001.
- 应答报文:可视为只有 TCP 报头,没有载荷.
- 意思就是 < 1001 的数据,B 已经收到了;接下来 A 要从 1001 开始往后发送!!!
TCP将每个字节的数据都进行了编号。即为序列号。
下图体现的是报文的字节:
由于 TCP 是面向字节流的,编号的时候,是按照字节来编的!
在确认应答的情况下,如果没有收到 ACK,就需要通过其他途径来处理!
超时重传:不是说没有收到 ACK,立即就放弃,就需要重新再发一遍!
网络的环境是非常复杂的,尤其是有些时候,网络会拥堵,拥堵就可能会导致丢包!
丢包,是 “无差别” 丢的。任何一个数据报,都有可能会丢包!
普通报文 可能丢失,ACK 也可能丢失!
业务数据丢失
发送方等待一定的时间之后,没有收到 ACK 就会重传!
ACK 丢失
业务数据已经到了 主机 B 了,反馈的 ACK 没有回过去,发送方等待一会之后,就触发了重传!
假设第一次重传失败了,进行第二次重传,又失败了;
第一次丢包超时时间为 t1,第二次丢包超时时间为 t2,此时一定:t1 < t2
丢包超时等待的时间间隔,随着丢包此时的增加,越来越大!
连续重传之后又丢包的次数越多,此时意味着单次发送的丢包概率越大,那么可能是网络上遇到了非常严重的故障,短期内恢复不了;发送的再频繁也没有用!
- 如果连续几次重传都不行,那就只能放弃了!
- 超时重传也不会无限制的重传下去,尝试几次之后,仍无法传输,就会放弃尝试,并断开连接!
确认应答 和 超时重传 可以认为是保证 TCP 可靠性的 最核心机制!
但是 连接管理 是面试中最高频的问题(网络知识)!
在正常情况下,TCP 要经过 三次握手 建立连接,四次挥手 断开连接!
三次握手:必须是客户端主动,服务器被动
经历这四次交互,就完成了建立连接的过程,其实是两对操作,客户端和服务器,互相给对方发送了一个 SYN,再互相给对方发送了一个 ACK,一共是四次交互,完成了这个过程!
但是因为中间的两次 即 服务器给 客户端发送 SYN 和 ACK,都是内核收到 A 的 SYN 之后,立即返回的,可以合并为一次!
所以整个过程又叫 “三次握手”。
三次握手的意义:(三次握手,认为是一种保证可靠性的机制)
四次挥手:客户端和服务器都可以主动
与 三次握手 不同,四次挥手 看起来也是双方各自给对方发送 FIN,各自给对方发送 ACK。
但是,四次挥手 这里的 中间两次,不能合并!
B 返回 ACK 是 内核 的行为,操作系统内容接收到 FIN 之后,就会立即返回 ACK;
而接下来 B 返回 FIN 是用户代码的行为,用户在代码中调用 socket.close 方法,才会触发 FIN!
因此 B 发送 FIN 和 发送 ACK 之间会有不可忽视的时间间隔,正因为有了时间间隔,就不能合并了
举例:
完整过程:
TCP 的状态:
我们要清楚一点:**可靠性 和 效率是冲突的!**保证 可靠性 肯定会影响到 效率 的。
TCP 在保证 可靠性 的前提下,尽可能的提高 效率。
滑动窗口机制的本质就是把等待 ACK 的时间重叠起来。
减少等待时间,就相当于提高了效率。
每次传输,都需要等待 ACK,收到 ACK 再发下一题数据,这样效率就很低。
我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)。
- 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000 个字节(四个段)。
- 发送前四个段的时候,不需要等待任何ACK,直接发送;
- 收到第一个 ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;
- 操作系统内核为了维护这个滑动窗口,需要开辟 发送缓冲区 来记录当前还有哪些数据没有 应答;只有确认应答过的数据,才能从缓冲区删掉;
- 窗口越大,则网络的吞吐率就越高;
我们之前提到了TCP 在保证 可靠性 的前提下,尽可能的提高 效率。 那么在滑动窗口之下,可靠性是否有影响呢?
- 确认应答:还是正常应答,没有什么影响。
- 超时重传:在滑动窗口下,丢包了,怎么办?
对于超时重传丢包,这里分两种情况讨论。
情况一:ACK 丢失
这种情况下,部分 ACK 丢了并不要紧,因为可以通过后续的 ACK 进行确认;
情况二:数据包丢失
主机 A 发了半天之后,看到了连续的好几个 1001,它就明白了,是 1001 这个数据丢了!
接下来,A 就会重传 1001 这个数据了。
此处的原则是:哪条丢了,就重传哪条;已经传输到的数据,不必重复传输!
这种机制被称为 “快速重传”(不是说重传的有多快,而是说没有冗余的操作)
滑动窗口,窗口大小越大,发送速率就越快!流量控制,就是在针对发送速率进行制约!
接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应,反而还降低了速率。
流量控制,就是通过 接收缓冲区 剩余空间大小,来作为下一次发送时候的窗口大小。
我们之前了解到 16位 即 64 KB,那么是否意味着窗口大小最大就是 64 KB呢?并不是,这个是可选项
流程演示:
流量控制,站在接收方的角度,来控制发送速率;
但是整体的传输,其实不光有发送方和接收方,还有中间的一系列用来转发的设备。
拥塞控制,采取的方法:做实验。
通过实验的方式,找出一个合适的窗口大小。
- 刚开始按照小的窗口来发送。
- 如果不丢包,说明网络中间环境 比较畅通,就可以逐渐放大发送窗口的大小。
- 放大到一定程度,速率已经比较快,网络上就容易出现拥堵,进一步出现丢包;当发送方发现丢包之后,就减小发送的窗口。
反复在 2 和 3 之间循环!
这个过程,就达到了一个 “动态平衡”,发送速率不慢,接近了能承载的极限,同时还可以尽量少丢包,还能适应网络环境的动态变化。
流量控制 和 拥塞控制 都能影响发送方的滑动窗口大小!最终的滑动窗口大小,就取决于两者的较小值。
像上面这样的拥塞窗口增长速度,是指数级别的。“慢启动” 只是指初使时慢,但是增长速度非常快。
- 为了不增长的那么快,因此不能使拥塞窗口单纯的加倍。
- 此处引入一个叫做慢启动的阈值
- 当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长
拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。
延时应答也是一个用来 提高效率的机制。
延时应答,则是让窗口能够大一些。
在流量控制中,通过 ACK 告知发送方,窗口大小是多少合适,这里的窗口大小是由接收缓冲区的空余空间来决定的。
- 如果立即返回 ACK,可能接收端缓冲区空余空间为 5KB;
- 稍等一会(例如 500 ms),在这个过程中,应用程序不断的取走数据,接收端缓冲区空余空间可能为 100 KB 了。
在延时应答下,ACK 不一定要和发送的数据表一一对应,少点也是可以的。
那么所有的包都可以延迟应答么?肯定也不是;
- 数量限制:每隔N个包就应答一次;
- 时间限制:超过最大延迟时间就应答一次;
具体的数量和超时时间,依操作系统不同也有差异;一般N取2,超时时间取 200ms;
正常来说,ACK 是收到请求之后,内核立即返回的;而响应数据,则是应用程序代码,发送的。二者是不同的时机,就不能把 ACK 和 响应报文 合并。
但是基于延时应答等的基础上,延时一会,就可能和返回 响应数据,时间上重合了。
响应在收到请求之后,多长时间之内返回?不确定:
面向字节流,指的是读写载荷数据的时候,是按照 “字节流” 的方式来读取的。
TCP 数据报,本身仍然是 一个一个 “数据报” 这样的方式来传输的。
(应用程序,是感受不到从哪里到哪里是一个数据报的)
传输数据的时候,数据会先写入 接收缓冲区,应用程序直接从 接收缓冲区 取数据。
此时,应用程序在读取数据的时候,就可以灵活的进行了,可以一次读 M 个字节,分 N 次读。
如果一个 TCP 连接,里边只传一个 应用层数据包,这个时候不会粘包(短链接)。
如果一个 TCP 连接,传输多个应用层数据包,这个时候就容易分不清,从哪到哪是一个完整了应用层数据(长连接)。这就是粘包问题。
不仅仅是 TCP ,只要是面向字节流的传输,都有粘包问题(文件传输)。
粘包问题的解决方案:在应用程序代码中,明确包之间的边界!
按照程序关机,会先杀死所有的用户进程(也就包括我们自己写的 TCP 程序)
杀死进程 => 释放进程 PCB => 释放文件描述符表上对应的文件资源(相当于调用 close)
这个时候就会出发 FIN,开启 四次挥手 的流程!
- 如果四次挥手挥完了,就继续关机;
- 如果还没有挥完,就已经关机了,对端重传 FIN 若干次,没有响应,就放弃了。
同上,程序是正常关闭,还是异常崩溃,都会释放 PCB,都会释放文件描述符表(相当于调用 close)
也还是会正常 四次挥手(虽然进程没了,但是本身 TCP 连接也是内核负责,内核仍然会继续完成后续的挥手过程)
笔记本还好(内置电源),如果是台式机之类的,直接没了,肯定来不及挥手。
接收方 如果一段时间没有收到数据,就会定期给 发送方,发送 “心跳包”:
接收方 给对方发一个特殊的报文(ping),发送方 返回一个特殊的报文(ping)。
和主机掉电,相同。
为什么TCP这么复杂?因为要保证可靠性,同时又尽可能的提高性能。
可靠性:
提高性能:
其他:
当然,也包括你自己写TCP程序时自定义的应用层协议;
源端口号
发送方
目的端口号
接收方
UDP长度
最大接收长度为 65535 字节 即 64 KB.
校验和
可以认为是针对数据特征进行的 “摘要”,接收方就可以根据校验和来进行检查了!
网络传输中,传输的数据,不一定是准确无误的!
本质上是光信号/电信号,使用不同频率的光信号,表示 1-0,使用不同电频的电信号,表示 1-0;传输过程中,信号是可能受到干扰的!
干扰就可能造成 “比特反转”(1 和 0 互换)
接收方,收到了数据之后,就需要验证,当前的数据是否正确!
UDP传输的过程类似于寄信。
知道对端的IP和端口号就直接进行传输,不需要建立连接;
没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;
应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并; 用UDP传输100个字节的数据:
如果发送端一次发送100个字节,那么接收端也必须一次接收100个字节;而不能循环接收10次,每次接收10个字节。
UDP只有接收缓冲区,没有发送缓冲区: UDP没有真正意义上的
发送缓冲区。发送的数据会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;
UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃;
UDP的socket既能读,也能写,这个概念叫做 全双工
UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)。
当然,也包括你自己写UDP程序时自定义的应用层协议。
这是一个经典面试题:
以上两个问题答案类似,都可以参考TCP的可靠性机制在应用层实现类似的逻辑:
例如:
- 引入序列号,保证数据顺序;
- 引入确认应答,确保对端收到了数据;
- 引入超时重传,如果隔一段时间没有应答,就重发数据;
- ……
归根结底,TCP和UDP都是程序员的工具,什么时机用,具体怎么用,还是要根据具体的需求场景去判定。
协议头格式如下:
DHCP:动态分配 IP 地址
NAT:IP 地址转换
把 IP 地址分成两个大类:
- 内网 IP(局域网中使用的 IP)
- 外网 IP(广域网中使用的 IP)
允许局域网之间的内网 IP 重复,但是外网 IP 要保持唯一。
同一个局域网中的 IP 地址不能相同,但是不同局域网中的 IP 允许重复。
NAT 机制的本质就是用一个 外网 IP 代表一大批 内网的设备!
IPv6 相当于是另一个网络层的协议,和 IPv4 可以视为是完全不同的两个协议,而不是 IPv4 的升级版。
IPv6 使用 16字节(128位);IPv4 使用 4字节 (32位)。
IPv6 的 IP 地址是非常多的,可以说根本用不完。
但是 IPv6 有一个很大的问题:IPv6 和 IPv4 是不兼容的!
现存的支持 IPv4 的网络设备(路由器,网卡,交换机,…)不一定支持 IPv6。
要想升级,就得换设备,换设备,就要花钱,这个事情就给 IPv6 的普及带来了很大的阻碍!
2019年,由国家推进 IPv6,然后各大公司不计成本的升级 IPv6;如今,国内 IPv6 普及度已经非常高了。那么为什么国家要推进 IPv6 呢?
有了 IPv6,家里的设备就可以直接在外网访问了;
IPv4 的话,得通过特殊手段(内网穿透),才能做到。
路由选择 就和 地图寻路 差不多的。从 A 到 B,路线规划的过程中,就是路由选择。
路由器撒花姑娘进行路径规划的时候,没有那么多空间来保存全局的信息。
每个路由器只能知道位置信息的一部分。
路由器这里的数据转发,就类似于没有百度地图之前的,原始的寻路方式,问路。
每次问路,就相当于经历了一次 “路由转发”。
每个人脑子里面记住的一些位置信息,称为 “路由表”。
路由器会根据 目的 IP 在路由表 中匹配:
- 如果匹配到了,就会按照制定的方向继续往下转发。
- 如果没有匹配到,会有一个默认等待方向(下一跳地址,路由表中的默认选项)。
以太网 协议,即插网线协议。平时插的网线,也叫做 “以太网线”
“以太网” 不是一种具体的网络,而是一种技术标准;既包含了数据链路层的内容,也包含了 一些物理层的内容。例如:规定了网络拓扑结构,访问控制方式,传输速率等;
以太网的帧格式如下:
MTU相当于发快递时对包裹尺寸的限制。这个限制是不同的数据链路对应的物理层,产生的限制。
- 以太网帧中的数据长度规定最小46字节,最大1500字节,ARP数据包的长度不够46字节, 要在后面补填充位;
- 最大值1500称为以太网的最大传输单元(MTU),不同的网络类型有不同的MTU;
- 如果一个数据包从以太网路由到拨号链路上,数据包长度大于拨号链路的MTU了,则需要对 数据包进行分片(fragmentation);
- 不同的数据链路层标准的MTU是不同的;
作用:ARP协议建立了主机 IP地址 和 MAC地址 的映射关系。
- 在网络通讯时,源主机的应用程序知道目的主机的IP地址和端口号,却不知道目的主机的硬 件地址;
- 数据包首先是被网卡接收到再去处理上层协议的,如果接收到的数据包的硬件地址与本机不 符,则直接丢弃;
- 因此在通讯前必须获得目的主机的硬件地址;
从浏览器中输入 URL 开始,到最终看到页面位置,中间发生了哪些事情?
上述过程是客户端给服务器发送请求的过程,后面服务器还要根据请求计算响应,把响应按照类似的流程转发给客户端。
数据链路层
网络层
传输层
应用层