1、RPC(远程过程调用)(远程过程调用)2RPCRPC机理机理l在单台机器上构建并测试应用程序,然后将程序划分为两个或多个程序片,加入通信协议以允许每片程序在单独的计算机上运行。l从一个程序片调用另一个程序片的过程称为远程过程调用,即RPC。lRPC是一个Client/Server模型,调用程序片(本地程序)称为rpc client,被调用程序片(远程程序)称为rpc server。3RPCRPC的通信模型的通信模型ClientSend(remote call pi()(发送“请求服务”信息)Receive(ans)接收回复信息server接收调用信息;抽取参数并分析;调用所指的过程;执行远程过
2、程返回执行结果Send(ans)发送回复信息等待回复请求服务等待调用继续返回调用结果4RPC的执行的执行Local return Local callClient ProcessOP4 Client-stub OP1RPC Routinewaitreceive transmit call work returnServer ProcessOP2 Server-stub OP3RPC Routinereceive transmit123456789105几个几个“经久不衰经久不衰”的重要问题的重要问题l数据表示如何统一?l远程程序如何表述?l如何获得远程程序?l语义问题6数据表示的问题数据表示的
3、问题7可能的解决方案可能的解决方案1(非对称方式(非对称方式)8可能的解决方案可能的解决方案2(对称方式)(对称方式)9数据表示:数据表示:XDRlXDR 是不同数据类型规范化的标准表示。通过使用一个标准的数据类型表示,即使数据源来自具有完全不同体系结构的主机,程序也可以确保能够正确地解释数据。l实践中,大多数程序在内部不使用 XDR。相反,它们使用程序正运行的计算机体系结构特定的数据类型表示。当程序需要和其它程序通信时,程序在发送该数据之前将其数据转变为 XDR 格式。反之,当接收数据的时候,它将 XDR 格式的数据转换为自己特定的数据类型表示。10XDR机制机制(1)创建一个XDR缓存;#
4、define BUFFERSIZE 4000 XDR*xdrs;char bufBUFFERSIZE;xdrmem_create(xdrs,buf,BUFFERSIZE,XDR_ENCODE);(2)使用类型转换例程将本地数据对象转换成外部数据表示;int i=200;xdr_int(xdrs,&i);11l常规类型转换例程 xdr_bool,xdr_int,xdr_float,xdr_string,xdr_vector,l复合类型转换 struct example int count;int values2;char buffer4;12xdr_example(XDR*xdrs,exampl
5、e*objp)if(!xdr_int(xdrs,&objp-count)return(FALSE);if(!xdr_vector(xdrs,(char*)objp-values,2,sizeof(int),(xdrproc_t)xdr_int)return(FALSE);if(!xdr_vector(xdrs,(char*)objp-buffer,4,sizeof(char),(xdrproc_t)xdr_char)return(FALSE);return(TRUE);13XDR数据表示实例数据表示实例14RPC interface(xxx.idl)struct example int cou
6、nt;int values2;char buffer4;program SQUAREPROG version SQUAREVERS int square(int)=1;void setExample(example)=2;=1;=0 x30090900;RPC server(远程程序远程程序)的表述的表述rpcgen xxx.idl xxx的的stub15RPC server的标识的标识program:32bit整数标识。version:一个整数标识。从1开始。proc:一个整数标识。从1开始。0用于测试。program的划分:0 x00000000-0 x1fffffff 系统使用0 x20
7、000000-0 x3fffffff 用户使用0 x40000000-0 x5fffffff0 x60000000-0 xffffffff 保留16远程程序名 远程程序号 描述portmap 100000 端口映射器端口映射器rstatd 100001 rstatdrusersd 100002nfs 100003 网络文件系统ypserv 100004 yp(现在叫做NIS)mountd 100005dbxd 100006ypbind 100007 NIS绑定程序walld 100008 rwalldyppasswdd 100009.RPC server的标识(续)的标识(续)17远程程序映射
8、到协议端口远程程序映射到协议端口l 静态端口映射:如portmap/111,nfs/2049l 动态端口映射:32位prog无法一一映射到16位的port上。解决方法:(1)RPC提供了一个动态端口映射器(portmapper);(2)每个RPC Server启动的时候向本机上运行的动态端口映射器注册自己的远程程序号、版本号以及动态获得的端口号;(3)RPC Client用远程程序号+版本号向远程主机上的portmapper 查询相应的动态端口号,一旦rpc client获得了rpc server的动态端口号,就可使用该端口与rpc server建立socket通信。18图示图示19语义问题语
9、义问题l故障发生位置 在被调用者接收到调用它的命令之前发生故障 在执行其过程体时,被调用者发生故障 被调用者正确地完成了其过程体的执行,但在把结果返回给调用者之前发生故障l故障引发的问题 N2 文件内容追加20语义规则语义规则lLast-of-many:对执行一个远程过程调用而言,被调用的过程可能执行若干次,但规定其最后一次执行的结果作为返回结果;lAt-most-once:若调用者收到了回复消息,则称被调用的过程正确地完成了它的一次(仅仅一次)执行。如果调用者没有收到回复消息,或者,如果调用者在获得回复消息之前发生故障,那么,这时的调用效果就看作是根本就没有执行相应的过程。21语义规则(续)
10、语义规则(续)lAt-least-once:远程调用过程至少执行一次,回复消息可能返回一次或多次;lExactly-once:若server正常,则远程过程恰好执行一次,并返回一个调用结果22RPC编程编程1、构建解决问题的常规应用程序;2、选择一组过程形成远程程序,以便将远程程序转移到远程机器中,通过这种方法将程序分解;3、为远程程序编写RPC界面(xxx.idl),包括远程的名字及其编号,还有对其参数的申明。选择远程程序号和版本号;4、运行rpcgen检查该界面,如果合法,便生成四个源代码文件:xxx.h(类型说明文件)、xxx_XDR.c(XDR转换例程)、xxx_clnt.c(客户端的
11、stub)以及xxx_svr.c(服务守护过程,服务端的stub),这些文件将在客户和服务器程序中使用;23RPC编程(续)编程(续)5、为客户端和服务器端编写stub接口例程;6、编译并链接客户程序。它由四个主要文件组成:去掉了远程过程的程序、客户端的stub(rpc生成)、客户端的stub接口以及XDR过程(rpc生成)。7、编译并链接服务器程序。它由四个主要文件组成:远程过程组成的程序、服务器的stub(rpc生成)、服务器端的stub接口以及XDR过程(rpc生成)。8、在远程机器上启动服务器,接着在本机上启动客户。24RPC编程方法编程方法xxx.idlrpcgenxxx_clnt.
12、cC编译器客户应用程序客户stub接口客户xxx.hxxx_xdr.cC编译器远程过程服务器stub接口服务器xxx_svr.c25RPC编程编程(步骤步骤1)/*square.c*/void main()int ret;ret=square(3);printf(“%d”,ret);int square(int x)return x*x;26RPC编程编程(步骤步骤2)/*square.c*/void main()int ret;ret=square(3);printf(“%d”,ret);/*square_srp.c*/int square(int x)return x*x;27RPC编程编
13、程(步骤步骤3)/*rsquare.idl*/program SQUAREPROG version SQUAREVERS int square(int)=1;=1;=0 x30090900;28RPC编程编程(步骤步骤4)rpcgen square.idl生成四个文件:square.h、square_clnt.c、square_svc.c和square_xdr.c。29/*square.h*/#define SQUAREPROG 0 x30090900#define SQUAREVERS 1#define square 1extern int*square_1(int*inarg_ptr,CL
14、IENT*clnt);/clients stubextern int*square_1_svc(int*,struct svc_req*rqstp);/servers stub30/*square_clnt.c*/static struct timeval TIMEOUT=25,0;int*square_1(int*argp,CLIENT*clnt)static int clnt_res;memset(char*)&clnt_res,0,sizeof(clnt_res);if(clnt_call(clnt,square,/过程号:1(xdrproc_t)xdr_int,(caddr_t)arg
15、p,(xdrproc_t)xdr_int,(caddr_t)&clnt_res,TIMEOUT)!=RPC_SUCCESS)return(NULL);return(&clnt_res);31lclnt_call,远程过程调用函数。l参数说明:clnt,远程调用句柄远程调用句柄 square,服务函数,服务函数 xdr_int,输入参数编码例程,输入参数编码例程 argp,输入参数地址 xdr_int,输出参数编码例程,输出参数编码例程 clnt_res,输出参数地址32/*square_svr.c*/static void squareprog_1(rqstp,transp)/服务守护过程st
16、ruct svc_req*rqstp;register SVCXPRT*transp;union int square_1_arg;argument;int*result;33 switch(rqstp-rq_proc)case square:/过程号过程号:1 memset(char*)&argument,0,sizeof(argument);svc_getargs(transp,xdr_int,(caddr_t)&argument);result=square_1_svc(&argument,rqstp);svc_sendreply(transp,xdr_int,result);break
17、;return;34main()SVCXPRT*transp;transp=svcudp_create(RPC_ANYSOCK);if(!svc_register(transp,SQUAREPROG,SQUAREVERS,squareprog_1,IPPROTO_UDP)fprintf(stderr,unable to register(SQUAREPROG,SQUAREVERS,udp);exit(1);transp=svctcp_create(RPC_ANYSOCK,0,0);if(!svc_register(transp,SQUAREPROG,SQUAREVERS,squareprog_
18、1,IPPROTO_TCP)fprintf(stderr,unable to register(SQUAREPROG,SQUAREVERS,tcp);exit(1);35lsvcudp_create/svctcp_create 在在udp或者或者tcp协议上建立服务协议上建立服务lsvc_register 将守卫过程注册 SQUAREPROG,SQUAREVERS,为远程服务提供者的服务名和版本 squareprog_1,为接收到rpc调用请求时,转到的守卫过程名l守卫过程 struct svc_req*rqstp;里面包含了请求调用的函数名 通过svc_getargs、svc_sendrep
19、ly函数来接收参数和返回运行结果。36RPC编程编程(步骤步骤5)/*square_cif.c*/extern CLIENT*handle;static int*ret;int square(int x)int*arg;arg=&x;ret=square_1(arg,handle);return ret=0?-1:*ret;37/*square_sif.c*/static int retcode;int square_1_svc(int*arg,struct svc_req*rqstp)retcode=square(*arg);return retcode;38RPC编程编程(步骤步骤6)/*
20、square.c*/#define RMACHINE “202.115.30.151”CLIENT*handle;int square(int x);void main()int ret;handle=clnt_create(RMACHINE,SQUAREPROG,SQUAREVERS,”tcp”);ret=square(3);printf(“%d”,ret);3940RPC编程(步骤编程(步骤7)%cc o square square.c square_xdr.c square_clnt.c square_cif.c%cc o squared square_srp.c square_xdr.c square_svr.c square_sif.c41RPC编程(步骤编程(步骤8)%squared&%square 9%42小结:小结:RPC开发调用模型开发调用模型