【TCP/IP】IP协议

  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本

点击上方蓝字关注我,我们一起学编程
欢迎小伙伴们分享、转载、私信、赞赏

小伙伴儿们看完以后可不可以帮我点亮一下在看呀~

网际协议(IP)


网际协议 IP 是 TCP/IP 体系中两个最重要的协议之一,也是最重要的互联网标准协议之一,分为 IPv4 和 IPv6 两种。

与 IP 协议配套使用的还有三个协议:

  • 地址解析协议 ARP(Address Resolution Protocol)
  • 网际控制报文协议 ICMP(Internet Control Message Protocol)
  • 网际组管理协议 IGMP(Internet Group Management Protocol)

图片1

上图表示的是这三个协议与网际协议 IP 的关系。在这一层中,ARP 在最下面,因为 IP 经常要使用这个协议。ICMP 和 IGMP 在上面,因为它们要使用 IP 协议。

由于网际协议 IP 是用来使互联起来的多台计算机能够进行通信的,因此 TCP/IP 体系中的网络层常常被称为网际层或 IP 层。

在讨论网际协议 IP 之前,必须了解什么是虚拟互连网络。

1.1 虚拟互连网络

将全世界数以亿计的计算机都互连起来,并能够互相通信,是一个极其复杂的任务,也没有一种单一的网络能够使用所有用户的需求。

从一般的概念来讲,将网络互相连接起来需要使用一些中间设备。根据中间设备所在的层次,可以有以下四种不同的中间设备:

  • 物理层使用的中间设备叫做转发器(repeater)
  • 数据链路层使用的中间设备叫做网桥或桥接器(bridge)
  • 网络层使用的中间设备叫做路由器(router)
  • 在网络层以上使用的中间设备叫做网关(gateway)

当中间设备是转发器或网桥时,仅仅是将网络扩大了,而从网络层的角度来看,这仍然是一个网络,一般不称之为网络互连。网关比较复杂,目前使用得较少。因此,现在我们讨论网络互连时,都是指用路由器进行网路互连和路由选择。

路由器其实就是一台专用计算机,用来在互联网中进行路由选择。

下图表示许多计算机通过一些路由器进行互连。

图片2

由于参加互连的计算机网络都是用相同的网际协议 IP ,因此可以把互连以后的计算机网络看成是下图所示的虚拟互连网络

图片3

所谓虚拟互连网络,意思就是互连起来的各种物理网络的异构性本来是客观存在的,但是我们利用 IP 协议就可以使这些性能各异的网络在网络层上看起来好像是一个统一的网络

使用 IP 网络的好处是:当 IP 网上的主机进行通信时,就好像在单个网络上通信一样,他们看不见互连的各网络的具体异构细节。如果在这种覆盖全球的 IP 网的上层使用 TCP 协议,那么就是现在的互联网(Internet)。

当许多异构网络通过路由器互连起来时,如果所有的网络都使用相同的 IP 协议,那么在网络层讨论的问题就显得十分方便。下面举个例子说明。

如下图所示的互联网中,源主机 H1 要把一个 IP 数据报发送给目的主机 H2 。过程如下:
主机 H1 先查找自己的路由表,看目的主机是否就在本网络中。如是,则不需要经过任何路由器就直接交付;如不是,则必须把 IP 数据包发送给某个路由器(R1)。R1 在查找了自己的路由表后,知道应当把数据转发给 R2 进行间接交付。这样一直转发下去,直到最后路由器 R5 知道自己是和 H2 连接在同一个网络上,不需要再使用别的路由器转发了,于是就把数据报直接交付给目的主机 H2 。

图片4

我们注意到,主机的协议栈共有五层,但路由器的协议栈只有下三层。我们还能注意到,在 R4 和 R5 之间使用了卫星链路,而 R5 所连接的是个无线局域网。在 R1 到 R4 之间可以是任意类型的网络。总之,这里强调的是:互联网可以由多种异构网络互连组成。

如果我们之只从网络层考虑问题,那么 IP 数据报就可以想象成是在网络层中传送,其传送路径是:H1->R1->R2->R3->R4->R5->H2 。

1.2 分类的 IP 地址

在 TCP/IP 体系中,IP 地址是一个最基本的概念。

1.2.1 IP 地址及其表示法

整个的互联网就是一个单一的、抽象的网络。IP 地址就是给互联网上的每一台主机(或路由器)的每一个接口分配一个在全世界范围内是唯一的 32 位的标识符。IP 地址的结构使我们可以在互联网上很方便地进行寻址。IP 地址现在由互联网名字和数字分配机构 ICANN 进行分配。

IP 地址的编址方式经过了三个历史阶段。

  • 分类的 IP 地址
  • 子网的划分
  • 构成超网

所谓“分类的 IP 地址”就是将 IP 地址划分为若干个固定类,每一类地址都由两个固定长度的字段组成。其中第一个字段是网络号(net-id),它标志主机(或路由器)所连接到的网络。一个网络号在整个互联网范围内必须是唯一的。另一个字段是主机号(host-id),它标志该主机(或路由器)。一台主机号在它前面的网路号所指明的网络范围内必须是唯一的。

由此可见,一个 IP 地址在整个互联网范围内是唯一的

这种两级的 IP 地址可以记为:

IP 地址 := { <网络号>, <主机号> }

下图给出了各种 IP 地址的网络号字段和主机号字段,这里 A 类、B 类、C 类地址都是单播地址(一对一通信),是最常用的。

图片5

从上图可以看出:

  • A 类、B 类和 C 类地址的网络号字段分别为 1 个、2 个和 3 个字节长,而在网络号字段的最前面有 1~3 位的类别位,其数值分别规定为 0、10、110 。
  • A 类、B 类和 C 类地址的主机号字段分别为 3 个、2 个、1 个字节长。
  • D 类地址(前 4 位是 1110)用于多播(一对多通信)。
  • E 类地址(前 4 位是 1111)保留为以后用。

这里要指出,由于近年来已经广泛使用无分类 IP 地址进行路由选择,A 类、B 类和 C 类地址的区分已成为历史,这里介绍仅仅是为了从概念的演讲上更清晰。

从 IP 地址的结构来看,IP 地址并不仅仅指明一台主机,而且还指明了主机所连接到的网络。

当初将地址划分为 A 类、B 类和 C 类三个类别是出于这样的考虑:各种网络的差异很大,有的网络拥有很多主机,而有的网络上的主机则很少。当 IP 地址分类是为了更好地满足不同用户的要求,当某个单位申请到一个 IP 地址时,实际上是获得了具有同样网络号的一块地址。其中具体的各台主机号则由该单位自行分配,只要做到在该单位管辖的范围内无重复的主机号即可。

对于主机或路由器来说,IP 地址都是 32 位的二进制代码。为了提高可读性,我们将每 8 位翻译成一个等效的十进制数字,并在数字之间加上一个点,这就是点分十进制记法(dotted decimal notation)。如:128.11.3.31 。

1.3 IP 地址与硬件地址

  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本

在学习 IP 地址时,很重要的一点就是要弄懂主机的 IP 地址与硬件地址的区别。下图说明了这两种地址的区别。

图6

从层次的角度看,物理地址是数据链路层和物理层使用的地址,而 IP 地址是网络层及其以上各层使用的地址,是一种逻辑地址(之所以称其为逻辑地址是因为,IP 地址是用软件实现的额)。

在发送数据时,数据从高层下到低层,然后才到数据链路上传输。使用 IP 地址的 IP 数据报一旦交给了数据链路层,就被封装成 MAC 帧了。MAC 帧在传送时使用的源地址和目的地址都是硬件地址,这两个硬件地址都写在 MAC 帧的首部中。

连接在通信链路上的设备(主机或路由器)在收到 MAC 帧时,根据 MAC 帧首部中的硬件地址决定收下或丢弃。只有在剥去 MAC 帧的首部和尾部后把 MAC 层的数据上交给网络层后,网络层才能在 IP 数据报的首部中找到源 IP 地址和目的 IP 地址。

总之,IP 地址放在 IP 数据报的首部,而硬件地址则放在 MAC 帧的首部。在网络层及以上使用的是 IP 地址,而数据链路层及以下使用的是硬件地址。

强调几点:

  • 在 IP 层抽象的互联网上只能看到 IP 数据报
  • 虽然在 IP 数据报首部有源站 IP 地址,但路由器只根据目的站的 IP 地址的网络号进行路由选择
  • 在局域网的链路层,只能看见 MAC 帧

尽管互连在一起的网络的硬件地址体系各不相同,但 IP 层抽象的互联网却屏蔽了下层这些复杂的细节。只要我们在网络层上讨论问题,就能够使用统一的、抽象的 IP 地址研究主机和主机(路由器)之间的通信。

1.4 地址解析协议 ARP

在上面的介绍中,我们尚有一个问题待解决:主机或路由器怎么知道应当在 MAC 帧的首部填入什么样的硬件地址?

在实际应用中,我们经常会遇到这样的问题:已经知道了一个设备的 IP 地址,需要找出其相应的硬件地址。**地址解析协议(ARP)**就是用来解决这样的问题的。

下图说明了 ARP 协议的作用:从网络层使用的 IP 地址,解析出在数据链路层使用的硬件地址。

图片7

我们知道,网络层使用的是 IP 地址,但在实际网络的链路上传送数据帧时,最终还是必须使用该网路的硬件地址。但 IP 地址和下面的网络的硬件地址之间由于格式不同而不存在简单的映射关系,此外,在一个网络上可经常会有新的主机加入进来,或撤走一些主机。更换网络适配器也会使主机的硬件地址改变。

地址解析协议 ARP 解决这个问题的方式是在主机 ARP 高速缓存中存放一个从 IP 地址到硬件地址的映射表,并且这个映射表还经常动态更新(新增或超时删除)。每一台主机都设有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到硬件地址的映射表,这些都是该主机目前知道的一些地址。

那么主机怎么知道这些地址呢?

例如:当主机 A 要向本局域网上的某台主机 B 发送 IP 数据报时,就先在其 ARP 高速缓存中车看有无主机 B 的 IP 地址。若有,就在 ARP 高速缓存中查出其对应的硬件地址,再把这个硬件地址写入 MAC 帧,然后通过局域网把该 MAC 帧发往此硬件地址。

在一些情况下,也可能查询不到。比如,主机 B 刚加电、才入网等,其高速缓存是空的。在这种情况下,主机 A 就自动运行 ARP ,按照下列步骤找出主机 B 的硬件地址。

  • ARP 进程在本局域网上广播发送一个 ARP 请求分组。内容(艺术修饰后)为:“我的 IP 地址是 209.0.0.5 ,硬件地址是 00-00-C0-15-AD-18。我想知道 IP 地址为 209.0.06 的主机的硬件地址。”
  • 在本局域网中的所有主机上运行的 ARP 进程都收到此 ARP 请求分组。
  • 主机 B 的 IP 地址与 ARP 请求分组中要查询的 IP 地址一致,就收下这个 ARP 请求分组,并向主机 A 发送 ARP 响应分组,同时在这个 ARP 响应分组中写入自己的硬件地址。内容(艺术修饰后)为:“我的 IP 地址是 209.0.0.6 ,我的硬件地址是 08-00-2B-EE-0A 。”

这里需要注意一点,虽然本局域网中的所有主机都收到了这个 ARP 请求分组,但由于其余的所有主机的 IP 地址都与 ARP 请求分组中要查询的 IP 地址不一致,因此都不理睬这个 ARP 请求分组,只有主机 B 给予响应。即 ARP 响应分组是普通的单播(从一个源地址发送到一个目的地址)。

  • 微信搜索:编程笔记本

  • 微信搜索:编程笔记本

  • 微信搜索:编程笔记本

  • 主机 A 收到主机 B 的 ARP 响应分组后,就在其 ARP 高速缓存中写入主机 B 的 IP 地址到硬件地址的映射。

可见 ARP 高速缓存非常有用。如果不使用 ARP 高速缓存,那么任何一台主机只要进行一次通信,就必须在网络上用广播方式发送 ARP 请求分组,这就使得网络上的通信量大大增加。 ARP 把已经得到的地址映射保存在高速缓存中,这样就使得该主机下次再和具有同样目的地址的主机通信时,可以直接从高速缓存中找到所需的硬件地址而不必再用广播方式发送 ARP 请求分组。

ARP 对保存在高速缓存中的每一个映射地址项目都设置生存时间,凡是超过生存时间的项目就从高速缓存中删除掉。这么做的原因是,防止对应主机硬件地址改变(更换网络适配器等)后,IP 地址不再和原来的硬件地址匹配了,此时必须进行广播发送 ARP 请求分组。

注意, **ARP 是解决同一个局域网上的主机或路由器的 IP 地址和硬件地址的映射问题。**若两个主机处于不用的网络中,就需要路由器的接入。从 IP 地址到硬件地址的解析式自动进行的,主机的用户对这种地址解析过程是不知道的。下面给出使用 ARP 的四种典型情况:

图片8

  • 发送方是主机(如 H1),要把 IP 数据报发送到同一个网络上的另一台主机(如 H2)。这时 H1 发送 ARP 请求分组(在网 1 上广播),找到目的主机 H2 的硬件地址。
  • 发送方是主机(如 H1),要把 IP 数据报发送到另一个网络上的一台主机(如 H3 或 H4)。这时 H1 发送 ARP 请求分组(在网 1 上广播),找到网 1 上的一个路由器 R1 的硬件地址。剩下的工作由路由器 R1 来完成。R1 要做的事情是下面两种情况之一。
  • 发送方是路由器(如 R1),要把 IP 数据报转发到与 R1 连接在同一个网络(网 2)上的主机(如 H3)。这时 R1 发送 ARP 请求分组(在网 2 上广播),找到目的主机 H3 的硬件地址。
  • 发送方是路由器(如 R1),要把 IP 数据报转发到网 3 上的一台主机(如 H4)。H4 与 R1 不是连接在同一个网络上。这时 R1 发送 ARP 请求分组(在网 2 上广播),找到连接在网 2 上的一个路由器 R2 的硬件地址。剩下的工作由这个路由器 R2 来完成。

在许多情况下需要多次使用 ARP ,但这是以上几种情况的反复使用而已。

现在有一个问题:**既然在网络链路上传送的帧最终是按照硬件地址找到目的主机的,那么为什么我们还要使用抽象的 IP 地址,而不直接使用硬件地址进行通信呢?这样似乎就可以免去使用 ARP 。**这个问题必须弄清楚。

由于全世界存在着各式各样的网络,它们使用不同的硬件地址。要是这些异构网络能够互相通信就必须进行非常复杂的硬件地址转换工作,因此由用户或用户主机来完成这些工作几乎是不可能的事。但 IP 编址把这个复杂问题解决了。连接到互联网的主机只需各自拥有一个唯一的 IP 地址,他们之间的通信就像连接在同一个网络上那样简单方便,因为上述的调用 ARP 的复杂过程是由计算机软件自动进行的,对用户来说是看不见这种调用过程的。
因此,在虚拟的 IP 网络上用 IP 地址进行通信给广大的计算机用户带来很大的方便。

1.5 IP 数据报的格式

IP 数据报的格式能够说明 IP 协议都具有什么功能。在 TCP/IP 的标准中,各种数据格式常常以 32 位(即 4 字节)为单位来描述。下图描述了 IP 数据报的完整格式。

图9

从上图可以看出,一个 IP 数据报由首部和数据部分两部分组成。首部的前一部分是固定长度,共 20 字节,是所有 IP 数据报必须具有的。在首部的固定部分的后面是一些可选字段,其长度是可变的。

1.5.1 IP 数据报首部的固定部分中的各字段
  • 版本
    占 4 位,指 IP 协议的版本。**通信双方使用的 IP 协议的版本必须一致。**目前广泛使用的 IP 协议版本号为 4 (即 IPv4)。关于以后要使用的 IPv6 (即版本 6 的 IP 协议)。
  • 首部长度
    占 4 位,可表示的最大十进制数值是 15 。请注意,首部长度字段所表示数的单位是 32 位字(一个 32 位字长是 4 字节)。因为 IP 首部的固定长度是 20 字节,因此首部长度字段的最小值是 5 (即二进制表示的首部长度是 0101)。而当首部长度为最大值 15 时(即二进制表示的 1111),就表明首部长度达到最大值 15 个 32 位字长,即 60 字节。**当 IP 首部的长度不是 4 字节的整数倍时,必须利用最后的填充字段加以扩充。**因此 IP 数据报的数据部分永远在 4 字节的整数倍时开始,这样在实现 IP 协议时较为方便。首部长度限制为 60 字节的缺点是有时可能不够用。但这样做是希望用户尽量减少开销。最常用的首部长度是 20 字节(即首部长度为 0101),这时不使用任何选项。
  • 区分服务
    占 8 位,用来获得更好的服务。这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。
  • 总长度
    **总长度指首部和数据之和的长度,单位为字节。**总长度字段为 16 位,因此数据报的最大长度为 2^16-1=65535 字节。然而实际上传送这么长的数据报在现实中是极少遇到的。

我们知道,在 IP 层下面的每一种数据链路层协议都规定了一个数据帧中的数据字段的最大长度,这称为最大传送单元 MTU(Mac Transfer Unit)

当一个 IP 数据报封装成链路层的帧时,此数据报的长度(首部+数据部分)一定不能超过下面的数据据链路层所规定的 MTU 值。例如,最常用的以太网就规定其 MTU 值是 1500 字节。若传送的数据报长度超过数据链路层的 MTU 值,就必须把过长的数据报进行分片处理。

虽然使用尽可能长的 IP 数据报会使传输效率得到提高(数据部分占比提高),但数据报短也有好处。每一个 IP 数据报越短,路由器转发的速度就越快。**IP 协议还规定,在互联网中的所有主机和路由器都必须要能够接受长度不超过 576 字节的数据报。**当主机需要发送长度超过 576 字节的数据报时,应当先了解一下,目的主机是否能接受所要发送的数据报长度。否则,就要进行分片。

  • 微信搜索:编程笔记本

  • 微信搜索:编程笔记本

  • 微信搜索:编程笔记本

  • 标识
    占 16 位,IP 软件在存储器中维持一个计数器,每产生一个数据报,计数器就加 1 ,并将此值赋给标识字段。但这个标识并不是序号,因为 IP 是无连接的服务,数据报不存在按序接收的问题。当数据报由于长度超过网络的 MTU 而必须分片时,这个标识字段的值就被复制到所有的数据报片的标识字段中。相同的标识字段的值使分片后的数据报片能正确地重装成为原来的数据报。

  • 标志
    占 3 位,但目前只有 2 位有意义。
    标志字段中的最低位记为 MF(More Fragment)。MF=1 表示后面还有分片的数据报。MF=0 表示这已是若干数据报片中的最后一个;
    标志字段中简的一位记为 DF(Don’t Feagment),意思是不能分片。只有当 DF=0 时才允许分片。

  • 片偏移
    占 13 位。片偏移指出:较长的分组在分片后,某片在原分组中的相对位置。也就是说,相对于数据字段的起点,该片从何处开始。片偏移以 8 个字节为偏移单位。这就是说,每个分片的长度一定是 8 字节(64 位)的整数倍。
    下图说明了一个数据报(首部 20 字节,数据部分 3800 字节)的分片情况。

图片10

图片11

  • 生存时间
    占 8 位,生存时间字段常用的英文缩写是 TTL(Time To Live),**表明数据报在网络中的寿命,由发出数据包的源点设置这个字段。其目的是防止无法交付的数据报无限制地在互联网中兜圈子。路由器在每次转发数据报之前就把 TTL 值减 1 。若 TTL 值减小到零,就丢弃这个数据报,不再转发。**由于字段长度为 8 位,所以数据报在互联网中经过的最大路由器数量为 255 。若将数据报的 TTL 值设为 1 ,则该数据报只能在本局域网内传送,不能经过路由器。
  • 协议
    占 8 位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的 IP 层知道应将数据部分上交给哪个协议进行处理。
    下图列出一些常用的协议及其协议字段值。

图片12

  • 首部校验和
    占 16 位,这个字段只检验数据报的首部,不包含数据部分。这是因为数据报每经过一个路由器,路由器都要重新计算首部检验和(一些字段,如生存时间、标志、片偏移都可能发生变化)。不检验数据部分可减少计算的工作量。为了进一步减小计算检验和的工作量,IP 首部的检验和不采用复杂的 CRC 检验码,而采用下面的简单计算方法。

图片13

在发送方,先把 IP 数据报首部划分为许多 16 位字的序列,并把检验和字段置零。用反码算术运算(从低位到高位逐位进行计算,0+0=0,0+1=1,1+1=0 并进位,若最高位相加后产生进位,则最后得到的结果要加 1)把所有 16 位字相加后,将得到的和的反码写入检验和字段。接收方收到数据报后,将首部的所有 16 位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。若首部未发生任何变化,则此结果必为 0 ,于是就保留这个数据报。否则即认为出现差错,并将此数据报丢弃。

  • 源地址
    占 32 位。
  • 目的地址
    占 32 位。
1.5.2 IP 数据报首部的可变部分

IP 数据报首部的可变部分就是一个选项字段。选项字段用来支持排错、测量以及安全等措施,内容很丰富。此字段的长度可变,从 1 个字节到 40 个字节不等,取决于所选择的项目。某些项目只需要 1 个字节,它只包含 1 个字节的选项代码。而有些选项需要多个字节,这些选项一个个拼接起来,中间不需要有分隔符,最后用全 0 的填充字段补齐成为 4 字节的整数倍。

增加首部的可变部分是为了增加 IP 数据报的功能,但这同时也使得 IP 数据报的首部长度成为可变的。这就增加了每一个路由器处理数据报的开销。实际上这些选项很少被使用。很多路由器都不考虑 IP 首部的选项字段,因此新的 IP 版本 IPv6 就把 IP 数据报的首部长度做成固定的

1.6 IP 层转发分组的流程

下面我们用一个简单的例子来说明路由器是怎样转发分组的。下图是一个路由表的简单例子。

图片14

图中,有 4 个 A 类网络通过三个路由器连接在一起。每个网络上可能有成千上万台主机,可以想象,若路由表指出每一台主机应该怎样转发,则所得出的具有表就会过于庞大(如果每一个网络有 1 万台主机,四个网络就有 4 万台主机,因为每一个路由表就有 4 万个项目,即 4 万行。每一行对应于一台主机)。但若路由表只指出到某个网络应如何转发,则每个路由器中的路由表就只包含 4 个项目(即只有 4 行,每一行对应于一个网络)。

以路由器 R2 的路由表为例。由于 R2 同时连接在网络 2 和网络 3 上,因此只要目的主机在网络 2 或网络 3 上,都可通过接口 0 或 1 由路由器 R2 直接交付(当然还要利用地址解析协议 ARP 才能找到这些主机相应的硬件地址)。若目的主机在网络 1 中,则下一跳路由器应为 R1 ,其 IP 地址为 20.0.0.7 。路由器 R2 和 R1 由于同时连接在网络 2 上,因此从路由器 R2 把分组转发给路由器 R1 是很容易的。同理,若目的主机在网络 4 中,则路由器 R2 应把分组转发给 IP 地址为 30.0.0.1 的路由器 R3。

注意:图中每个路由器都有两个不同的 IP 地址。

可以把整个网络拓扑简化为下图所示。

图片15

在上述简化图中,网络变成了一条链路,但每一个路由器旁边都注明其 IP 地址。使用这样的简化图,可以使我们不必关心某个网络内部的具体拓扑以及连接在该网络上有多少台主机,因为这些对于研究分组转发问题并没有什么关系。简化图强调了在互联网上转发分组时,是从一个路由器转发到下一个路由器

总之,在路由表中,对每一条路由最主要的是以下两个信息:(目的网络地址,下一跳地址)。于是,我们就根据目的网络地址来确定下一跳路由器,这样做可以得出以下的结果。

  • IP 数据报最终一定可以找到目的主机所在的网络上的路由器(通过多次间接交付)。
  • 只有到达最后一个路由器时,才试图向目的主机进行直接交付。

这里我们需要强调一下,**路由表并没有给出分组指明到某个网络的完整路径(即先经过哪一个路由器,然后再经过哪一个路由器等)。路由表指出,到某个网络应当先到某个路由器(即下一跳路由器),在到达下一跳路由器后,再继续查找其他路由表,知道再下一步应当到哪一个路由器。**这样一步一步地查找下去,直到最后到达目的网络。

  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本
  • 微信搜索:编程笔记本
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值