TCP/IP详解 卷1:协议 学习笔记 第二十九章 网络文件系统

NFS(网络文件系统)使客户可以透明地访问服务器上的文件和文件系统。NFS的基础是RPC。

两个常用的网络编程API:socket和TLI(运输层接口,Transport Layer Interface)。通信的双方可使用不同的API。

RPC可以在用户程序编写时调用服务器的函数,实际发生的动作如下:
1.客户程序调用远程的过程时,它实际上只是调用了一个位于本机的函数,这个函数称为客户stub,客户stub将过程的参数封装成一个网络报文,并将这个报文发给服务器程序。

2.服务器主机上的一个服务器stub接收这个网络报文,从网络报文中提取参数,然后调用服务器的过程。

3.服务器函数将返回值返回给服务器stub,服务器stub将返回值封装成一个网络报文,发给客户stub。

4.客户stub从接收到的网络报文中取出返回值,并返回给客户程序。

RPC程序包好处如下:
1.应用程序设计员只需编写客户程序和被客户程序调用的服务器过程,很少或几乎没有涉及网络编程。

2.如果使用了不可靠的协议,如UDP,像超时重传等细节由RPC程序包来处理。

3.RPC库为参数和返回值的传输提供数据转换,如RPC程序包处理整数和浮点数在客户机和服务器主机上存储的不同形式,简化了在异构环境中的客户和服务器的编码问题。

两个常用的RPC程序包是Sun RPC和开放软件基金会(OSF)分布式计算环境(DCE)的RPC程序包。

Sun RPC有两个版本,一个版本建立在socket API基础上,和TCP和UDP打交道;另一个建立在TLI API基础上,称为TI-RPC(独立于运输层的),和内核提供的任何运输层协议打交道。本章讨论前者。
在这里插入图片描述
上图是使用UDP时,一个Sun RPC调用报文的格式,IP首部和UDP首部是标准的首部,UDP首部以下是RPC程序包定义的部分。

事务标识符(XID)字段由客户设置,再由服务器返回,如果客户收到的XID与服务器返回的不匹配,客户就放弃这个报文。每次客户发出一个新的RPC,就会改变一次报文的XID,但如果是客户重传一个以前发过的RPC(没有收到服务器的应答),重传报文的XID不会修改。

调用字段在调用报文中置0,在应答报文中置1。

上图中RPC版本字段表示当前的RPC版本是2。

程序号、版本号、过程号标识了服务器上被调用的特定过程。

证书字段标识了客户,有时证书字段为空值,有时是数字形式的客户的用户号和组号。服务器可以查看证书字段以决定是否执行请求的过程。

验证字段用于使用了DES加密的安全RPC。

证书字段和验证字段是可变长度字段,它们的长度也作为字段的一部分被编码。

过程参数字段的格式依赖于远程过程的定义。服务器stub用UDP数据报大小减去其他所有字段的长度就是参数字段的大小。如果使用的是TCP协议,由于TCP是一个字节流协议,没有记录边界,所以没有固定的长度,为此,在TCP首部和XID之间增加了一个4字节的长度字段,告诉接收者这个RPC调用由多少字节组成,这使得一个RPC调用报文在必要时可用多个TCP段来传输。
在这里插入图片描述
应答报文的XID字段是从调用报文的XID字段复制而来。应答字段设为1。如果调用报文被接受,状态字段设为0(如果RPC版本不为2或服务器不能鉴别客户身份,调用报文可能会被拒绝)。安全的RPC使用验证字段来标识服务器。

如果远程过程调用成功,接受状态字段置为0,一个非0值可能标识一个不合法的版本号或过程号。

如果使用的是TCP而非UDP,则在TCP首部和XID字段之间插入一个4字节的长度字段。

外部数据表示(XDR,eXternal Data Representation)是一个标准,用来对RPC调用报文和应答报文中的值(RPC首部字段、过程参数、过程结果)进行编码。采用标准化的方法对这些值编码使一个系统中的客户可以调用另一个不同架构的系统中的一个过程。

XDR定义了很多数据类型以及它们如何传输(如比特顺序、字节顺序等),发送者必须使用XDR格式构造一个RPC报文,接收者将XDR格式报文转换为本机的表示形式。

XDR支持的数据类型包括整数、无符号整数、布尔类型、浮点数、定长数组、可变长数组、结构。

RPC服务器使用的是临时端口,Sun RPC中,使用端口映射器跟踪哪一个RPC程序使用了哪个临时端口。

端口是Internet协议族的特征,TI-RPC可以工作在任何运输层协议之上,而不仅仅是TCP和UDP,所以使用TI-RPC的系统中,端口映射器的名字是rpcbind。

端口映射器本身必须有一个知名端口(111),它也是一个RPC服务器程序。服务器使用RPC调用向端口映射器注册自身,客户使用RPC调用向端口映射器查询。端口映射器提供4个服务过程:
1.PMAPPROC_SET:一个RPC服务器启动时调用这个过程,注册一个程序号、版本号、端口号、协议。
2.PMAPPROC_UNSET:RPC服务器调用此过程删除一个已经注册的映射。
3.PMAPPROC_GETPORT:一个RPC客户启动时调用此过程,根据程序号、版本号、协议来获得注册的端口号。
4.PMAPPROC_DUMP:返回端口映射器数据库中的所有记录。

RPC服务器启动到RPC客户调用过程:
1.RPC服务器系统引导前,端口映射器必须首先启动(端口映射器创建一个TCP监听,端口为111,同时也创建一个UDP监听,端口也是111)。

2.RPC服务器启动时,为每个支持的程序版本都创建一个TCP监听和UDP监听,各自绑定一个临时端口(两端口号是否一致无关紧要)。服务器通过RPC调用端口映射器的PMAPPROC_SET过程,注册每一个程序、版本、协议、端口号。

3.RPC客户启动时,调用PMAPPROC_GETPORT过程获得一个指定程序、版本、协议的临时端口号。

4.客户发送一个RPC调用报文给3返回的端口号,如果使用的是UDP,客户只是发送一个包含RPC调用报文的UDP数据报到服务器相应的UDP端口,之后服务器发送一个包含RPC应答报文的UDP数据报到客户作为响应;如果使用的是TCP,客户会对服务器的TCP端口号做一个主动打开,然后在建立的TCP连接上发送一个RPC调用报文,服务器的RPC应答报文也在连接上发送。

rpcinfo程序打印了端口映射器中的映射记录,它调用了端口映射器的PMAPPROC_DUMP过程:
在这里插入图片描述
在这里插入图片描述
可见端口映射器中,每一个程序、版本号、协议的组合都有自己的端口号映射。NFS的安装守护程序的两个版本可通过同样的TCP端口号和同样的UDP端口号来访问,而NFS的加锁管理程序的每个版本都有各自不同的端口号。

NFS客户可透明地访问服务器上的文件和文件系统,这不同于提供文件传输服务的FTP,FTP会产生文件的一个完整副本,NFS只访问一个进程引用文件的那一部分,并且NFS使得这种访问透明,即任何能访问一个本地文件的客户程序不需修改就能访问一个NFS文件。

NFS是一个使用Sun RPC构造的客户服务器应用。NFS客户通过向NFS服务器发送RPC请求来访问其上的文件,尽管这一过程可以使用一般的用户进程实现,即NFS客户和服务器都是用户进程,但通常不这么实现,因为:
1.访问一个NFS文件必须对客户透明,因此NFS的客户调用是由客户操作系统代表用户进程来完成的。
2.出于效率考虑,NFS服务器在服务器操作系统中实现。NFS服务器如果是一个用户进程,每个客户请求和应答都要在内核和用户进程之间切换,代价太大。
在这里插入图片描述
对于上图,有以下需要注意的:
1.访问的是本地文件还是一个NFS文件对于客户来说是透明的,文件被打开时,内核决定这一点。

2.NFS客户通过它的TCP/IP模块向NFS服务器发送RPC请求,NFS主要使用UDP,最新的实现也使用TCP。

3.NFS服务器在端口2049接收作为UDP数据报的客户请求,尽管NFS可被实现成端口映射器,允许服务器使用一个临时端口,但大多实现都是直接指定UDP端口为2049。

4.当NFS服务器收到一个客户请求,它将这个请求传递给本地文件访问例程,后者访问服务器主机上的一个本地磁盘文件。

5.NFS服务器需要花一定时间来处理一个客户请求,这段时间内,服务器不应阻止其他客户的请求,为实现这一功能,大多NFS服务器是多线程的。

6.NFS客户也需要并发,因此客户内核中一般运行着多个NFS客户,具体实现依赖于操作系统。

大多Unix主机都能是一个NFS客户或服务器或两者都是。大多PC的实现都只提供了NFS客户实现。大多IBM大型机只提供了NFS服务器功能。

NFS不仅仅由NFS协议组成,以下是NFS使用的不同RPC程序:
在这里插入图片描述
上图的程序版本是SunOS 4.1.3中使用的。

客户访问服务器上的文件系统之前,NFS客户主机必须先调用服务器上的安装守护程序。

加锁管理程序和状态监视器允许客户锁定一个NFS服务器上文件的部分区域。这两个程序独立于NFS协议,因为加锁需要知道客户和服务器的状态,而NFS本身在服务器上是无状态的。

文件句柄用来引用服务器上的一个文件或目录,它是不透明的,不透明指服务器创建文件句柄,把它传递给客户,然后客户访问文件时,使用对应的文件句柄,但客户不会查看句柄的内容,它的内容只对服务器有意义。

每次客户进程打开一个位于NFS服务器上的文件时,NFS客户就会从NFS服务器获取该文件的一个文件句柄,每次NFS客户读写文件时,文件句柄就会传给服务器以指定被访问的文件。

一般,用户进程不会和文件句柄打交道,只有NFS客户和NFS服务器将文件句柄传来传去。第2版的NFS中的文件句柄占32字节,第3版中占64字节。

Unix服务器一般在文件句柄中存储以下信息:文件系统标识符(文件系统最大和最小设备号)、i-node号(在一个文件系统中唯一的数值)、i-node的生成码(每当一个i-node被一个不同文件重用时就改变的数值)。

NFS客户在访问服务器上一个文件系统中的文件之前,需要使用安装协议安装那个文件系统。一般这是在客户主机引导时完成的。

以下是一个Unix客户发出mount命令时发生的情况,它说明了一个NFS的安装过程:
在这里插入图片描述
上图中发生的动作解释:
1.服务器上的端口映射器在服务器主机引导时启动。安装守护程序mountd在端口映射器之后被启动,它监听一个TCP端口和一个UDP端口,两个都是临时端口,然后它在端口映射器中注册这些端口号。

2.在客户机上执行mount命令,它向服务器上的端口映射器发出一个RPC调用来获取服务器上安装守护程序的端口号。客户和服务器上端口映射器的交互可使用TCP也可使用UDP,但一般使用UDP。

3.端口映射器应答安装守护程序的端口号。

4.mount命令向安装守护程序发出一个RPC调用来安装服务器上的一个文件系统,这既可以使用TCP也可以使用UDP,但一般使用UDP。服务器可以验证客户,通过客户的IP和端口号来判别是否允许客户安装指定的文件系统。

5.安装守护程序应答,其中包含指定文件系统的文件句柄。

6.客户机上的mount命令发出mount系统调用,将5中返回的文件句柄与客户机上的一个本地安装点联系起来。文件句柄被存储在NFS客户中,从现在开始,用户对于服务器文件系统的任何引用都将从使用这个文件句柄开始。

以上过程将除了客户机上的mount系统调用外的处理都放在用户进程而非内核中。mount命令、端口映射器、安装守护程序都是用户进程。

在NFS客户机sun上执行:
在这里插入图片描述
执行结果如下:
在这里插入图片描述
当我们引用sun上的文件/nfs/bsdi/usr/rstevens/hello.c时,实际上引用的是服务器bsdi上的文件/usr/rstevens/hello.c

以下是NFS服务器提供的15个过程,尽管NFS被设计成可以在不同服务器上工作,但一些提供Unix功能的过程可能不被其他操作系统支持(如硬链接、符号链接、所属组、执行权等):
1.GETATTR:返回一个文件的属性:文件类型、访问权限、文件大小、文件属主、上次访问时间等信息。

2.SETATTR:设置一个文件的属性:只允许设置文件属性的一个子集:访问权限、文件属主、所属组、文件大小、上次访问时间、上次修改时间。

3.STATFS:返回一个文件系统的状态:可用空间大小、最佳传送大小等。Unix的df命令使用此过程。

4.LOOKUP:查找一个文件。每当用户打开一个NFS服务器上的文件时,NFS客户调用此过程。

5.READ:从一个文件读数据。客户用此过程时要说明文件的句柄、读操作的开始位置、读数据的最大字节数(最多8192字节)。

6.WRITE:对一个文件写操作。客户用此过程时要说明文件的句柄、开始位置、写数据的字节数、要写的数据。

7.CREATE:创建一个文件。

8.REMOVE:删除一个文件。

9.RENAME:重命名一个文件。

10.LINK:为一个文件构造一个硬链接。硬链接是一个Unix的概念,指磁盘中可以有任意个目录项指向它。

11.SYMLINK:为一个文件创建一个符号链接。符号链接是包含另一个文件名字的文件。大多数引用符号链接的操作实际上引用的是符号链接所指的文件。

12.READLINK:读一个符号链接,即返回符号链接所指的文件的名字。

13.MKDIR:创建一个目录。

14.RMDIR:删除一个目录。

15.READDIR:读一个目录。Unix的ls命令使用此过程。

以上过程名都有一个前缀NFSPROC_,上面省略了。

NFS最初是用UDP写的,所有厂商都提供了这种实现,一些新实现也支持TCP。TCP支持主要用于广域网,使文件操作更快。

当从LAN转换到WAN时,网络的动态特征变化得非常大,往返时间变动范围大,拥塞经常发生,WAN的这些特征是我们考虑使用具有TCP属性的算法(慢启动)从而避免拥塞,而UDP没有提供类似的东西,只能在NFS客户和服务器上加上同样的算法或使用TCP。

伯克利实现的Net/2 NFS支持UDP和TCP,使用TCP时的不同如下:
1.服务器主机引导时,它启动一个NFS服务器,TCP NFS服务器被动打开TCP端口2049,等待客户连接请求。而UDP NFS服务器在UDP端口2049等待UDP数据报。

2.客户使用TCP安装服务器上的文件系统时,NFS客户对服务器上的TCP端口2049做一个主动打开,这样为这个文件系统在客户和服务器间形成了一个TCP连接。如果同样的客户在同样的服务器上安装另一个文件系统,会创建另一个TCP连接。

3.客户和服务器在连接两端都要设置TCP的keepalive选项,这样双方都能检测到对方主机崩溃或崩溃后的重启动。

4.客户方所有使用这个服务器文件系统的应用共享这个TCP连接。

5.如果客户检测到服务器已崩溃(收到连接超时)或崩溃后重启动(收到对方复位连接),它尝试与服务器重新建立连接,之后,在以前连接上超时的所有客户请求在新的连接上都会重新发出。

6.如果客户崩溃并重新启动后,它可能还会使用TCP重新安装服务器的文件系统,这导致和服务器的另一个连接。而此时客户与服务器之间的前一个连接处于半打开状态(服务器认为它还开着),但服务器由于设置了keepalive选项,服务器发出下一个keepalive探查报文时,这个半打开的TCP连接会被终止。

当tcpdump检测到一个包含RPC调用(调用字段为0)、目的端口是2049的UDP数据报时,它把数据报按NFS请求进行解码。

读一个NFS文件:
在这里插入图片描述
当cat上图中文件时,sun的内核检测到这是NFS服务器上的文件系统,就使用NFS去访问文件。以下是tcpdump的输出:
在这里插入图片描述
tcpdump解析NFS请求或应答报文时,它打印客户的XID字段而非端口号,第一行和第二行中的XID字段值为0x7aa6。

客户内核中的打开函数依次处理路径中的目录,当处理到/nfs/bsdi/usr时,它发现这是一个指向已安装的NFS文件系统的一个安装点。

第1行中客户调用GETATTR过程取得客户已经安装的服务器目录(/usr)的属性。第2行中,应答成功返回。

第3行客户调用LOOKUP过程查看rstevens文件,第4行中应答成功返回。此次LOOKUP调用时客户使用了远程文件系统被安装时由客户内核保存的文件句柄,而应答中包含了下一步要使用的新的文件句柄。

第5行客户使用第4行返回的文件句柄对hello.c调用LOOKUP过程。第6行返回了要引用的文件/nfs/bsdi/usr/rstevens/hello.c的文件句柄,可见客户对正在打开的文件的路径上的每个成员都调用了一次LOOKUP过程。

第7行客户又调用了一次GETATTR过程,接着在第9行调用了READ过程,客户请求从偏移0开始的1024个字节,但接收到的没有这么多。

以上过程中,应用进程不知道内核所做的这些RPC调用。应用进程只是调用了内核的open函数,这引起了3个RPC请求和应答(第1~6行),然后应用又调用了内核的read函数,这引起了2个RPC请求和应答(第7~10行)。该文件位于NFS文件服务器这一点对于客户应用来说是透明的。

在NFS服务器上创建一个目录:
在这里插入图片描述
以下是tcpdump的输出:
在这里插入图片描述
改变目录引起客户调用了2次GETATTR过程(第1~4行)。创建目录时,调用了一次GETATTR过程(第5、6行)和一次LOOKUP过程(第7、8行),调用LOOKUP过程用于验证要创建的目录是否存在,应答OK不代表目录存在,它只是代表过程返回了。

NFS是无状态的,服务器不记录哪个客户在访问文件,前面的NFS过程中并没有open和close服务器上的文件,LOOKUP过程与open类似,但服务器不知道客户对一个文件调用了LOOKUP过程后是否会读写该文件。

无状态设计的理由是为了在服务器崩溃并重启动时,简化服务器的崩溃恢复操作。

下例是从一个崩溃后重启动的NFS服务器上读取一个文件的过程,除了在服务器崩溃到重新启动完成这一时间段内的暂停外,客户并不知道发生了什么,客户应用进程没有受到影响。

在客户sun上,对一个svr4主机上的NFS服务器上的长文件/usr/share/lib/termcap执行cat命令,在传送过程中把以太网网线拔掉,关闭然后重启动服务器主机,再重新将网线连上,客户的NFS read过程每次读1024字节,以下是tcpdump的输出:
在这里插入图片描述
第1~10行对应客户打开文件的过程。在第11行对文件进行了第1个READ操作,并在第12行返回了1024字节的数据,这个读文件操作一直重复到第129行。

在第130和131行有两个请求超时,并分别在第132和133行重传,此处有两个读请求的原因在于,客户内核检测到客户应用进程在顺序地进行读操作,所以试图预先取得数据块(大多Unix内核都采用了这种预读技术)。客户内核运行着多个NFS块IO守护程序,它们代表客户产生多个RPC请求(上例中一个守护程序正从偏移65536处读8192个字节,另一个正在从73728处预读8192个字节)。

客户重传发生在130~168行,在169行服务器已经重启动,在服务器对168行的客户NFS请求做出应答前,它发送了一个ARP请求,对168行的响应在171行被发送,之后客户继续READ。

在服务器重启动后,先处理了偏移65536的请求,又处理了下一个偏移65560的请求,对于另一个NFS块IO守护程序的偏移73728的请求没有处理,原因是服务器看到了168行的请求,而两个块IO守护程序的时间差为0.74秒,只有在168行请求的0.74秒后才会重发偏移73728的请求。

客户只是感觉到了从129行到171行这5分钟的暂停。

对于上例中客户的重传间隔,需要知道有两个客户守护程序,它们各自有自己的超时时间,可见NFS客户使用了这样的超时定时器:间隔为0.875秒的倍数,上限是20秒,每次超时后,重传间隔翻倍,0.875、1.75、3.5、7.0和14.0。

客户有两个选项可控制重传,如果客户主机上的服务器文件系统是硬安装的,客户会永远重传下去,如果是软安装的,客户重传了固定次数后就会放弃。硬安装情况下,客户有一个选项决定是否允许用户中断无限制的重传,如果客户主机安装服务器文件系统时允许用户中断无限制的重传,就可以键入一个中断键终止客户应用。

如果上例中,在服务器崩溃后重启前给它换了一块网卡,那么服务器的物理地址就被改变了,由上图可知,服务器启动时没有发送免费ARP(因此客户的ARP高速缓存中还是旧的服务器物理地址)。服务器为了能应答客户的NFS请求,必须向客户sun发送一个ARP请求查询sun的物理地址,之后NFS客户收到了服务器的ARP请求,客户就会把ARP请求中的服务器的新硬件地址更新到自己的ARP高速缓存。

如果一个RPC过程被服务器执行多次仍返回同样的结果,就把它叫作等幂过程。

NFS的读过程是等幂的,服务器多次执行READ时,同一个文件的同一部分被重读一次。

NFS的读操作是等幂的是因为每个READ请求都指出了读操作开始的偏移位置,如果有一个NFS过程要求服务器读一个文件的下N个字节,该过程就不是等幂的了,除非服务器被做成有状态的,如果一个应答丢失了,客户重发读下N个字节的READ请求,返回的结果将与丢失的应答中的结果不一样。

并不是所有的NFS文件系统操作都是等幂的,如客户NFS发出UDP REMOVE请求删除一个文件,服务器删除文件后,回答OK,但回答丢失,客户NFS超时,又发送一个REMOVE请求,这次服务器找不到指定文件,返回错误,客户应用程序收到一个错误表示文件不存在,但该文件是存在的只是已经被删除了。而如果使用的是TCP,服务器在发出应答后没收到ack,会超时重传丢失的应答。

等幂的NFS过程有:GETATTR、STATFS、LOOKUP、READ、WRITE、READLINK、READDIR,不等幂的有:CREATE、REMOVE、RENAME、LINK、SYMLINK、MKDIR、RMDIR。SETATTR过程如果不是用来截断文件是等幂的。

UDP可能会发生响应报文丢失的现象,NFS服务器通过以下方法处理非等幂操作:大多服务器实现了一个最近应答的高速缓存,用来存放非等幂操作最近的应答。每当服务器收到一个请求,它首先检查高速缓存,如果找到了匹配项,就返回以前的应答,不再调用相应NFS过程。

等幂服务器过程的概念可用于任何基于UDP的应用程序,如DNS也提供了一个等幂服务,一个DNS服务器可以任意多次地执行一个解析者的请求而没有任何不良后果。

NFS V3与V2的区别:
1.V2中的文件句柄是32字节的固定大小数组,V3中,它变成了一个最多64字节的可变长度数组。在XDR中,一个可变长度的数组被编码为一个4字节的数字,后跟实际的数组字节。这样实现时减少了文件句柄的长度,如Unix只需要12字节,但又允许非Unix实现维护另外的信息。

2.V2将每个READ和WRITE RPC过程可以读写的数据限制为8192字节,这个限制在V3中取消了,这意味着UDP的NFS实现中,读写数据长度只受到IP数据报大小的限制(65535字节)。

3.文件大小以及READ和WRITE过程开始偏移的字节从32字节扩充到64字节,允许读写更大的文件。

4.每个影响文件属性值的调用都返回文件的属性,减少了用户调用GETATTR过程的次数。

5.WRITE过程在V2中是同步的,在V3中可以是异步的。

6.V3中删去了过程STATFS,增加了7个过程:ACCESS(检查文件访问权限)、MKNOD(创建一个Unix特殊文件)、READDIRPLUS(返回一个目录中的文件名和它们的属性)、FSINFO(返回一个文件系统的静态信息)、FSSTAT(返回一个文件系统的动态信息)、PATHCONF(返回一个文件的POSIX.1信息,如文件名的最大长度、路径的最大长度以及文件系统支持的操作等)、COMMIT(将以前的异步写操作提交到外存)。

一个Unix系统中的RPC服务器使用临时端口而非知名端口的原因在于,一个进程必须有超级用户权限才能给自己分配一个小于1024的端口号,这对于系统提供的服务器没问题,如Telnet服务器、FTP服务器、端口映射器,但我们不想给所有RPC服务器提供这个权限。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值