天天看点

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

本节书摘来自异步社区《windows网络与通信程序设计(第3版)》一书中的第1章,第1.3节,作者: 陈香凝 , 王烨阳 , 陈婷婷 , 张铮 更多章节内容可以访问云栖社区“异步社区”公众号查看。

编写网络程序,必须要有一种机制来标识通信的双方。本节详细讨论internet中各层的寻址方式,以及相关的寻址协议。

1.3.1 mac地址

网络通信的最边缘便是lan了,我们先来看看在lan中是如何寻址的。

1.mac子层和mac地址

lan主要使用广播通信。在其内部,许多主机连在相同的通信通道上,通信时的关键问题是当竞争存在时如何决定谁使用通道。解决此问题的协议属于链路层的子层,称为mac(medium access control,介质访问控制)子层。mac子层在lan中特别重要,因为广播通信是由它控制的。

网络中的节点(主机或者路由器)都有链路层地址。事实上,并不是节点有链路层地址,而是节点的适配器有。链路层地址通常叫做lan地址、物理地址或者mac地址(本书统一使用mac地址)。mac地址的长度为6字节,共有248种可能的取值。这个6字节地址通常以十六进制表示,每个字节都用一对十六进制数表示,如e6-e9-00-17-bb-4b。

适配器在生产时就被永久性地安排了一个mac地址,它记录在适配器的rom中,是不可改变的。另外,mac地址空间是由ieee管理的,它保证所有适配器的mac地址都不相同。

2.局域网通信

当适配器想要发送一个帧到其他适配器时,发送适配器将目的适配器的mac地址插入到封包中,然后以广播的方式将此封包发送到lan中的每一台主机(除了它自己)。每个接收到封包的适配器都会查看包中的目的mac地址是否和自己的mac地址相同,如果相同就萃取出包含的数据报,并将其传递到协议堆栈的上层(网络层),如果不同就直接丢弃。这样一来,只有目的节点的适配器才对接收到的帧进行处理。

有的时候发送适配器想要lan中的所有其他适配器都接收并处理它发送的帧。这种情况下,发送适配器在目的地址域插入一个特定的mac广播地址即可。对使用6字节地址的lan来说,广播地址是48位全设为1的地址,即ff-ff-ff-ff-ff-ff。

3.广域网通信

mac地址仅应用在lan中,一旦封包从lan的网关出来进入internet,链路层地址就不再有用了,这个时候,各路由器是依靠下面所讲的网络层的ip地址来寻找目标主机或目标主机所在的lan的。

1.3.2 ip地址

互联网上的每个主机和路由器都有ip地址,它将网络号和主机号编码在一起。此组合是唯一的:原则上,互联网中没有两个机器有相同的ip地址。所有的ip地址都是32位长,在ip封包的源地址和目的地址域中使用。要注意,ip地址指定的并不是主机,而是网络接口(如网卡)。因此,如果一台主机有两个网络接口,它就必须有两个ip地址。不过,实际上,大部分主机都只有一个网络接口,也就只有一个ip地址。

几十年来,ip地址都被分成了5个类,如图1.3所示,这个分配方案称为分类编址方案。虽然这种方法现今已经不再使用了,但是在各种文献中还是很常见的。我们待会儿再讨论分类寻址的替换者,即现在使用的分类方法。

类别a、b、c,分别允许128个网络和16 000 000个主机、16 384个网络和64000个主机、2 000 000个网络和256个主机。类别d用于多播,在这里面,数据报被发送到多个主机。以1111开始的e类地址保留供今后使用。超过500 000个网络现在连接到了internet上,这个数目还在飞快地增加。网络号由非盈利公司icann(internet corporation for assigned names and numbers)管理以避免冲突。icann又委派地方权利机关管理部分地址空间,然后再分配给isp和其他公司。

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

网络地址是32位的数字,通常以点分十进制的形式写出。在这种格式下,每个4字节以十进制形式写出,值为0~255。例如,32位的十六进制地址c0290614写成十进制为192.41.6.20。最低的ip地址是0.0.0.0,最高的是255.255.255.255。

值0和-1(即所有位都是1)有特殊的意义,如图1.4所示。0的意思是本网络和主机,-1被用作广播地址来指定网络中的所有主机。

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

ip地址0.0.0.0由主机在引导时使用。网络号为0的ip地址表示当前网络。这些地址使得网络内的机器在不知道网络号的情况下就可以引用自己所在的网络(但是它们必须要知道它的类,以便知道包含多少个0)。完全包含1的地址允许在本地网络(通常是lan)上广播。带有恰当网络号和主机域全为1的地址允许机器发送广播包到internet上的任何远程lan(不过,大部分网管都禁止这种特性)。最后,所有127.xx.yy.zz形式的地址都被保留用作回环测试。发送到这个地址的封包不会被输出到线路上,它们被当作到来的封包直接在本地处理。这允许封包发送到本地网络而发送者不需要知道网络号。

1.3.3 子网寻址

1.子网的概念

使用上述经典分类方法遇到的问题是,单个a、b或者c类网络地址表示的是一个网络,而不是一组lan。为了更有效地利用ip地址,人们又将单个网络分成几个部分在内部使用,网络(这里是以太网)中的每个部分称为子网(subnet),一个lan就可以是一个子网。

一个网络分成多个子网之后,对外面的世界而言,它仍然是一个单独的网络。典型的校园网网络如图1.5所示。它们使用一个主路由器连接isp或者是地方网络,大量以太网分散在校园的不同部门内。每个以太网有自己的路由器,它们连接到主路由器上。

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

当一个封包到达主路由器时,它如何知道要传给哪个子网呢?一种方法是在主路由器中存放一个包含6 5536个入口的表,记录校内的每个主机都使用哪个路由器。这个方法可行,但是它需要在主路由器中存放非常大的表,当主机添加、移除或者终止服务时,要进行许多人工维护。

取而代之的是一种不同的方案。原来单独的b类地址中14位是网络号,16位是主机号,但是现在从主机号中拿出几位以创建子网号。例如,如果大学有35个部门,它可以拿出6位作为子网号,10位作为主机号,从而允许最多增加64个以太网,每个以太网可以最多容纳1022个主机。如果错误的话,以后还可以重新划分。

为了实施子网,主路由器需要子网掩码,它指定了“网络+子网+主机”的各个部分,如图1.6所示。子网掩码也以点分十进制形式写出,外加一个斜线,后跟“网络+子网”部分的位长度。例如在图1.6中,子网掩码可以写成255.255.252.0,也可以写为“/22”,表示子网掩码有22位长。

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

在网络外面,子网的划分是不可见的,因此申请一个新的子网不需要惊动icann。在上例中,第一个子网可以使用从130.50.4.1开始的ip地址,第二个子网从130.50.8.1开始,第三个子网从130.50.12.1开始,依此类推。为了看到为什么子网间隔数是4,看看这些地址对应的二进制数据就知道了。

子网1: 10000010 00110010 000001|00 00000001

子网2: 10000010 00110010 000010|00 00000001

子网3: 10000010 00110010 000011|00 00000001

这里,竖直线(|)显示了子网号和主机号之间的边界,它的左边是6位的子网号,右边是10位的主机号。

2.子网的工作方式

为了看清楚这些子网是如何工作的,有必要解释一下ip封包是如何在路由器中进行处理的。每个路由器有一个表,列出了一些这样的ip地址 ——(网络,0)和一些这样的ip地址——(本网络,主机)。第一种说明了封包如何进入远程网络。第二种说明了封包如何到达本地主机。与每个表相关联的是到达目的地要使用的网络接口和其他一些信息。

当ip封包到达时,路由器在路由表中查找它的目的地址。如果封包是到远程网络的,它就会在表中记录的接口上被转发到下一个路由器。如果封包是到本地主机的(例如,在路由器的lan上),就会被直接发往目的地。如果表中没有记录,就会被转发到有着更大路由表的默认的路由器上。这种方法意味着,每个路由器仅需要知道其他网络和本地主机,而不是(网络,主机)对,这极大地减小了路由表的大小。

当引入子网划分时,路由表也要改变,添加表的入口——(本网络,子网掩码,0)和(本网络,本子网掩码,主机)。这样,在子网k上的路由器便知道如何到达所有其他的子网,也知道如何到达子网k上的主机,而不需要知道其他子网上主机的详细信息。事实上,要做的所有改变是使每一个路由器对网络的子网掩码做一个and运算来去掉主机号,然后在表中查找它的地址。例如,一个封包寻址130.50.15.6,到达了主路由器,使用子网掩码255.255.252.0/22做and运算之后,得到地址130.50.12.0,然后在路由表中查找此地址以便知道使用哪条输出线可以到达3号子网。子网的划分就这样通过创建一个包含网络、子网和主机的3层结构减小了路由表空间。

1.3.4 端口号

网络层ip地址用来寻址指定的计算机或者网络设备,而传输层的端口号用来确定运行在目的设备上的哪个应用程序应该接收这个封包。端口号是16位的,范围为0~65 536。在设备上寻址端口号时经常使用的形式是“ip:portnumber”,例如,209.217.52.4:80。连接的两端都要使用端口号,但是没有必要相同。

许多公共服务都使用固定的端口号,例如,www(world wide web,万维网)默认使用的端口号为80,ftp(file transfer protocol,文件传输协议)使用的是21,e-mail使用25(smtp,简单邮件传输协议)和110(pop3,邮局协议)。自定义服务一般使用高于1 024的端口号。

1.3.5 网络地址转换(nat)

ip地址是短缺的资源。用完ip地址的问题并不是会发生在将来的理论问题,它现在就不断地在发生。一个isp可能有一个“/16”地址空间(b类地址),总共可以有65 534个主机号。如果它有更多客户的话,就会出现问题。

对整个internet来说,长期的解决方案便是迁移到ipv6,它有128字节地址。这个转化正在慢慢进行,但是要想真正地完成需要经过很多年的时间。这样,人们就必须找到一个快速的解决办法,能够马上投入使用。这个快速的办法便是nat(network address translation,网络地址转化),它在rfc3022中描述,下面笔者进行概括说明。

nat的基本思想是为每个公司分配一个ip地址(或者是很少几个)来进行internet传输。在公司内部,每个电脑取得一个唯一的ip地址来为内部传输做路由。然而,当封包离开公司,进入isp之后,就需要进行地址转化了。为了使这个方案可行,ip地址的范围被声明为私有的,公司可以随意在内部使用它们。仅有的规则是,没有包含这些地址的封包出现在internet上。3个保留的范围是:

10.0.0.0   ~10.255.255.255/8  (16 777 216台主机)

172.16.0.0  ~172.31.255.255/12  (1 048 576台主机)

192.168.0.0  ~192.168.255.255/16  (65 536台主机)

第一个范围提供了1 677 721个地址(照常,除了0和−1),大部分公司都选择这个范围,即使它们不需要这么多地址。

nat操作如图1.7所示。在公司内部,每个机器都有一个唯一的10.x.y.z形式的地址。然而,当封包离开公司时,它要经过nat盒,此盒将内部ip源地址,即图中的10.0.0.1转化成公司的真实地址,此例中为198.60.42.12。nat盒通常和防火墙一起绑定在一个设备上,这里的防火墙通过小心地控制进出公司的封包提供了安全保障。本书将在第12章讲述防火墙。也可以将nat盒与公司的路由器结合在一起(小的局域网通常是这样)。

《Windows网络与通信程序设计(第3版)》——1.3 网络程序寻址方式

到此为止,我们忽略了一个很小的细节:当应答返回时(例如,从一个web服务器),它自然是寻址198.60.42.12,那么,nat盒怎样知道该使用哪个地址替换它呢?这是nat要解决的问题。如果在ip头中有多余的域,这个域可以用来跟踪真正的发送者是谁,但是现在ip头中仅有1位还没有使用。原则上,可以创建一个新的ip头选项来保存真正的源地址,但是做这件事情需要在整个internet上改变所有机器的ip代码以便处理新的选项。作为一个快速解决办法,这实在不怎么样。

真正发生的事情是这样的。nat设计者观察到大多数ip封包都携带tcp或者udp净荷。在第8章学习tcp和udp时将会看到,它们都有包含源端口号和目的端口号的协议头。端口号是16位整型,它指示tcp连接从哪里开始和结束。这些端口号提供了使nat工作需要的域。

当进程想和远程进程建立tcp连接时,它在自己机器上绑定一个没有使用的tcp端口,这称为源端口号,它告诉tcp代码向哪里发送到来的封包。这个进程也提供了目的端口号,它说明了在远端将这个封包给谁。端口0~1024预留给众所周知的服务。例如,端口80是web服务器使用的端口,因此远程客户可以定位它们。每个外出的tcp消息都包含目的端口号和源端口号,这些端口号标识了在两个终端使用连接的进程。

使用源端口域能够解决上面的映射问题。每当一个外出的封包进入nat盒,10.x.y.z源地址被公司的真实地址替换。另外,tcp源端口号域被一个索引替换,该索引指向nat盒中有6 5536个表项的转换表。表中的表项包含了原来的ip地址和原来的源端口号。最后,ip头与tcp头的校验和都会被重新计算并插入到封包。替换源端口号是非常必要的,因为从机器10.0.0.1和10.0.0.2出发的连接可能恰巧使用了同一个端口,因此,端口号本身不足以标识发送进程。

当封包从isp到达nat盒时,tcp头中的源端口号被提取出来,用来在nat盒的映射表中当索引。从找到的表项中,内部ip地址和原来的tcp源端口号被提取出来,并插入到封包。然后,ip和tcp的校验和又重新计算,并插入到封包。最后,封包被传递到公司内部的路由器,使用10.x.y.z地址进行正常的发送。

nat也可以用来减轻adsl和电缆用户的ip短缺。当isp为每个用户分配一个地址时,它使用10.x.y.z地址,当来自用户的封包从isp退出,进入主要internet时,它们经由nat盒,nat盒将它们转化为真实的internet地址。在回来的路上,封包再经历相反的映射。从这个角度看,对于外部internet来说,isp和其adls/电缆用户就像一个大公司。

nat确实解决了ip地址短缺问题,但是它也带来了一些新的问题。本书后面会看到,nat的存在给开发点对点(p2p)应用程序带来了许多麻烦。因为nat设计时并没有考虑让它后面的主机去被动地接受连接,也就是说nat假设它后面的主机不做inernet服务器,所以要想让藏在nat之后的两台主机建立直接的tcp/udp连接,就不得不使用一个中介服务器来帮助它们完成初始化工作。

继续阅读