以下文字引用自http://www.yuanma.org/data/2006/0918/article_1560.htm
一、概述
在传统的编程概念中,过程是由程序员在本地编译完成,并只能局限在本地运行的一段代码,也即其主程序和过程之间的运行关系是本地调用关系。因此这种结构在网络日益发展的今天已无法适应实际需求。总而言之,传统过程调用模式无法充分利用网络上其他主机的资源(如CPU、 Memory等),也无法提高代码在实体间的共享程度,使得主机资源大量浪费。 |
而本文要介绍的RPC编程,正是很好地解决了传统过程所存在的一系列弊端。通过RPC我们可以充分利用非共享内存的多处理器环境(例如通过局域网连接的多台工作站),这样可以简便地将你的应用分布在多台工作站上,应用程序就像运行在一个多处理器的计算机上一样。你可以方便的实现过程代码共享,提高系统资源的利用率,也可以将以大量数值处理的操作放在处理能力较强的系统上运行,从而减轻前端机的负担。 |
二、RPC的结构原理及其调用机制 |
当然,一台服务主机上可以有多个远程过程提供服务,那么如何来表示一个唯一存在的远程过程呢?一个远程过程是有三个要素来唯一确定的:程序号、版本号和过程号。程序号是用来区别一组相关的并且具有唯一过程号的远程过程。一个程序可以有一个或几个不同的版本,而每个版本的程序都包含一系列能被远程调用的过程,通过版本的引入,使得不同版本下的RPC能同时提供服务。每个版本都包含有许多可供远程调用的过程,每个过程则有其唯一标示的过程号。 |
三、基于RPC的应用系统开发 |
通过以上对RPC原理的简介后,我们再来继续讨论如何来开发基于RPC的应用系统。一般而言在开发RPC时,我们通常分为三个步骤: |
a、定义说明客户/服务器的通信协议。 |
这里所说的通信协议是指定义服务过程的名称、调用参数的数据类型和返回参数的数据类型,还包括底层传输类型(可以是 UDP或TCP),当然也可以由RPC底层函数自动选择连接类型建立TI-RPC。最简单的协议生成的方法是采用协议编译工具,常用的有Rpcgen,我会在后面实例中详细描述其使用方法。 |
b、开发客户端程序。 |
c、开发服务器端程序。 |
开发客户端和服务器端的程序时,RPC提供了我们不同层次的开发例程调用接口。不同层次的接口提供了对RPC不同程度控制。一般可分为5个等级的编程接口,接下来我们分别讨论一下各层所提供的功能函数。 |
1、简单层例程 |
简单层是面向普通RPC应用,为了快速开发RPC应用服务而设计的,他提供了如下功能函数。 |
|
2、高层例程 |
在这一层,程序需要在发出调用请求前先创建一个客户端句柄,或是在侦听请求前先建立一个服务器端句柄。程序在该层可以自由的将自己的应用绑在所有的传输端口上,它提供了如下功能函数。 |
|
3、中间层例程 |
中间层向程序提供更为详细的RPC控制接口,而这一层的代码变得更为复杂,但运行也更为有效,它提供了如下功能函数。 |
|
4、专家层例程 |
这层提供了更多的一系列与传输相关的功能调用,它提供了如下功能函数。 |
|
5、底层例程 |
该层提供了所有对传输选项进行控制的调用接口,它提供了如下功能函数。 |
函数名 |
功能描述 |
Clnt_dg_create( ) |
采用无连接方式向远程过程在客户端建立客户句柄 |
Svc_dg_create( ) |
采用无连接方式建立服务句柄 |
Clnt_vc_create( ) |
采用面向连接的方式建立客户句柄 |
Svc_vc_create( ) |
采用面向连接的方式建立RPC服务句柄 |
Clnt_call( ) |
客户端向服务器端发送调用请求 |
program TESTPROG { version VERSION { string TEST(string) = 1; } = 1; } = 87654321; |
program RDICTPROG /* name of remote program ( not used ) */ { version RDICTVERS /* declaration of version ( see below ) */ { int INITW ( void ) = 1; /* first procedure in this program */ int INSERTW ( string ) = 2; /* second procedure in this program */ int DELETEW ( string ) = 3; /* third procedure in this program */ int LOOKUPW ( string ) = 4; /* fourth procedure in this program */ } = 1; /* definition of the program version */ } = 0x30090949; /* remote program number ( must be unique ) */ |
/* dict.c -- main, initw, nextin, insertw, deletew, lookupw */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define MAXWORD 50 /* maximum length of a command or word */ #define DICTSIZ 100 /* maximum number of entries in dictionary. */ char dict[DICTSIZ][MAXWORD + 1]; /* storage for a dictionary of words */ int nwords = 0; /* number of words in the dictionary */ /* 函数原型 */ int nextin(char *cmd, char *word); int initw(void); int insertw(const char *word); int deletew(const char *word); int lookupw(const char *word); /* ------------------------------------------------------------------ * main -- insert, delete, or lookup words in a dictionary as specified * ------------------------------------------------------------------ */ int main(int argc, char *argv[]) { char word[MAXWORD + 1]; /* space to hold word from input line */ char cmd; int wordlen; /* length of input word */ printf("Please input:/n"); while (1) { wordlen = nextin(&cmd, word); if (wordlen < 0) { exit(0); } switch (cmd) { case 'I': /* 初始化 */ initw(); printf("Dictionary initialized to empty./n"); break; case 'i': /* 插入 */ insertw(word); printf("%s inserted./n", word); break; case 'd': /* 删除 */ if (deletew(word)) { printf("%s deleted./n", word); } else { printf("%s not found./n", word); } break; case 'l': /* 查询 */ if (lookupw(word)) { printf("%s was found./n", word); } else { printf("%s was not found./n", word); } break; case 'q': /* 退出 */ printf("Program quits./n"); exit(0); break; default: /* 非法输入 */ printf("command %c invalid./n", cmd); break; } /* end of switch */ } /* end of while */ return 0; } /* end of main */ /* ------------------------------------------------------------------ * nextin -- read a command and(possibly) a word from the next input line * ------------------------------------------------------------------ */ int nextin(char *cmd, char *word) { int i, ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } *cmd = (char) ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } if (ch == '/n') { return (0); } i = 0; while (!isspace(ch)) { if (++i > MAXWORD) { printf("error: word too long./n"); exit(1); } *word++ = ch; ch = getc(stdin); } /* end of while */ *word = '/0'; /* 原来的代码这里有问题 */ return i; } /* end of nextin */ /* ------------------------------------------------------------------ * initw -- initialize the dictionary to contain no words at all * ------------------------------------------------------------------ */ int initw(void) { nwords = 0; return 1; } /* end of initw */ /* ------------------------------------------------------------------ * insertw -- insert a word in the dictionary * ------------------------------------------------------------------ */ int insertw(const char *word) { strcpy(dict[nwords], word); nwords++; return (nwords); } /* end of insertw */ /* ------------------------------------------------------------------ * deletew -- delete a word from the dictionary * ------------------------------------------------------------------ */ int deletew(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { nwords--; strcpy(dict[i], dict[nwords]); return (1); } } /* end of for */ return (0); } /* end of deletew */ /* ------------------------------------------------------------------ * lookupw -- look up a word in the dictionary * ------------------------------------------------------------------ */ int lookupw(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { return (1); } } /* end of for */ return (0); } /* end of lookupw */ |
/* dict1.c -- main, nextin */ #include <stdio.h> #include <stdlib.h> #define MAXWORD 50 /* maximum length of a command or word */ /* ------------------------------------------------------------------ * main -- insert, delete, or lookup words in a dictionary as specified * ------------------------------------------------------------------ */ int main(int argc, char *argv[]) { char word[MAXWORD + 1]; /* space to hold word from input line */ char cmd; int wordlen; /* length of input word */ printf("Please input:/n"); while (1) { wordlen = nextin(&cmd, word); if (wordlen < 0) { exit(0); } switch (cmd) { case 'I': /* 初始化 */ initw(); printf("Dictionary initialized to empty./n"); break; case 'i': /* 插入 */ insertw(word); printf("%s inserted./n", word); break; case 'd': /* 删除 */ if (deletew(word)) { printf("%s deleted./n", word); } else { printf("%s not found./n", word); } break; case 'l': /* 查询 */ if (lookupw(word)) { printf("%s was found./n", word); } else { printf("%s was not found./n", word); } break; case 'q': /* 退出 */ printf("Program quits./n"); exit(0); break; default: /* 非法输入 */ printf("command %c invalid./n", cmd); break; } /* end of switch */ } /* end of while */ return 0; } /* end of main */ /* ------------------------------------------------------------------ * nextin -- read a command and(possibly) a word from the next input line * ------------------------------------------------------------------ */ int nextin(char *cmd, char *word) { int i, ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } *cmd = (char) ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } if (ch == '/n') { return (0); } i = 0; while (!isspace(ch)) { if (++i > MAXWORD) { printf("error: word too long./n"); exit(1); } *word++ = ch; ch = getc(stdin); } /* end of while */ *word = '/0'; return i; } /* end of nextin */ |
/* dict2.c -- initw, insertw, deletew, lookupw */ #include <string.h> #define MAXWORD 50 /* maximum length of a command or word */ #define DICTSIZ 100 /* maximum number of entries in dictionary. */ char dict[DICTSIZ][MAXWORD + 1]; /* storage for a dictionary of words */ int nwords = 0; /* number of words in the dictionary */ /* ------------------------------------------------------------------ * initw -- initialize the dictionary to contain no words at all * ------------------------------------------------------------------ */ int initw(void) { nwords = 0; return 1; } /* end of initw */ /* ------------------------------------------------------------------ * insertw -- insert a word in the dictionary * ------------------------------------------------------------------ */ int insertw(const char *word) { strcpy(dict[nwords], word); nwords++; return (nwords); } /* end of insertw */ /* ------------------------------------------------------------------ * deletew -- delete a word from the dictionary * ------------------------------------------------------------------ */ int deletew(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { nwords--; strcpy(dict[i], dict[nwords]); return (1); } } /* end of for */ return (0); } /* end of deletew */ /* ------------------------------------------------------------------ * lookupw -- look up a word in the dictionary * ------------------------------------------------------------------ */ int lookupw(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { return (1); } } /* end of for */ return (0); } /* end of lookupw */ |
/* rdict.x */ /* RPC declarations for dictionary program */ const MAXWORD = 10; /* maximum length of a command or word */ const DICTSIZ = 3; /* number of entries in dictionary */ struct example /* unused structure declared here to */ { int exfield1; /* illustrate how rpcgen builds XDR */ char exfield2; /* routines to convert structures */ }; /* ------------------------------------------------------------------ * RDICTPROG -- remote program that provides insert, delete, and lookup * ------------------------------------------------------------------ */ program RDICTPROG /* name of remote program ( not used ) */ { version RDICTVERS /* declaration of version ( see below ) */ { int INITW ( void ) = 1; /* first procedure in this program */ int INSERTW ( string ) = 2; /* second procedure in this program */ int DELETEW ( string ) = 3; /* third procedure in this program */ int LOOKUPW ( string ) = 4; /* fourth procedure in this program */ } = 1; /* definition of the program version */ } = 0x30090949; /* remote program number ( must be unique ) */ |
rpcgen -Ss -o rdict_srv_func.c rdict.x |
rpcgen -Sc -o rdict_client.c rdict.x |
rpcgen -Sm rdict.x > Makefile |
# This is a template Makefile generated by rpcgen # Parameters CLIENT = rdict_client SERVER = rdict_server SOURCES_CLNT.c = SOURCES_CLNT.h = SOURCES_SVC.c = SOURCES_SVC.h = SOURCES.x = rdict.x TARGETS_SVC.c = rdict_svc.c rdict_xdr.c TARGETS_CLNT.c = rdict_clnt.c rdict_xdr.c TARGETS = rdict.h rdict_xdr.c rdict_clnt.c rdict_svc.c OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o) OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o) # Compiler flags CFLAGS += -g LDLIBS += -lnsl RPCGENFLAGS = # Targets all : $(CLIENT) $(SERVER) $(TARGETS) : $(SOURCES.x) rpcgen $(RPCGENFLAGS) $(SOURCES.x) $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c) $(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c) $(CLIENT) : $(OBJECTS_CLNT) $(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) $(SERVER) : $(OBJECTS_SVC) $(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS) clean: $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER) |
# This is a template Makefile generated by rpcgen # Parameters CLIENT = rdict_client SERVER = rdict_server SOURCES_CLNT.c = SOURCES_CLNT.h = SOURCES_SVC.c = SOURCES_SVC.h = SOURCES.x = rdict.x TARGETS_SVC.c = rdict_svc.c rdict_xdr.c rdict_srv_func.c TARGETS_CLNT.c = rdict_clnt.c rdict_xdr.c rdict_client.c TARGETS = rdict.h rdict_xdr.c rdict_clnt.c rdict_svc.c OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o) OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o) # Compiler flags CFLAGS += -g LDLIBS += -lnsl RPCGENFLAGS = # Targets all : $(CLIENT) $(SERVER) $(TARGETS) : $(SOURCES.x) rpcgen $(RPCGENFLAGS) $(SOURCES.x) $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c) $(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c) $(CLIENT) : $(OBJECTS_CLNT) $(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) $(SERVER) : $(OBJECTS_SVC) $(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS) clean: $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER) *~ |
/* * This is sample code generated by rpcgen. * These are only templates and you can use them * as a guideline for developing your own functions. */ #include "rdict.h" /* ------------------------------------------------------------------ * nextin -- read a command and(possibly) a word from the next input line * ------------------------------------------------------------------ */ int nextin(char *cmd, char *word) { int i, ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } *cmd = (char) ch; ch = getc(stdin); while (isspace(ch)) { ch = getc(stdin); } /* end of while */ if (ch == EOF) { return (-1); } if (ch == '/n') { return (0); } i = 0; while (!isspace(ch)) { if (++i > MAXWORD) { printf("error: word too long./n"); exit(1); } *word++ = ch; ch = getc(stdin); } /* end of while */ *word = '/0'; return i; } /* end of nextin */ void rdictprog_1(char *host) { CLIENT *clnt; int *result_1; char *initw_1_arg; int *result_2; char *insertw_1_arg; int *result_3; char *deletew_1_arg; int *result_4; char *lookupw_1_arg; #ifndef DEBUG clnt = clnt_create(host, RDICTPROG, RDICTVERS, "udp"); if (clnt == NULL) { clnt_pcreateerror(host); exit(1); } #endif /* DEBUG */ char word[MAXWORD + 1]; /* space to hold word from input line */ char cmd; int wordlen; /* length of input word */ while (1) { printf("/nPlease input:"); wordlen = nextin(&cmd, word); if (wordlen < 0) { exit(0); } /* printf("/nYour cmd is:%c, your word is:%s/n", cmd, word); */ switch (cmd) { case 'I': /* 初始化 */ result_1 = initw_1((void *) &initw_1_arg, clnt); /* printf("/nYour result is:%d/n", *result_1); */ if (result_1 == (int *) NULL) clnt_perror(clnt, "call failed"); else if(*result_1 ==0) printf("Dictionary initialized to empty./n"); else printf("Dictionary have already initialized./n"); break; case 'i': /* 插入 */ insertw_1_arg = word; result_2 = insertw_1(&insertw_1_arg, clnt); /* printf("/nYour result is:%d, your string is:%s(%d)/n", *result_2, insertw_1_arg, strlen(insertw_1_arg)); */ if (result_2 == (int *) NULL) clnt_perror(clnt, "call failed"); else printf("%s inserted./n", word); break; case 'd': /* 删除 */ deletew_1_arg = word; result_3 = deletew_1(&deletew_1_arg, clnt); /* printf("/nYour result is:%d, your string is:%s(%d)/n", *result_3, deletew_1_arg, strlen(deletew_1_arg)); */ if (result_3 == (int *) NULL) clnt_perror(clnt, "call failed"); else printf("%s deleted./n", word); break; case 'l': /* 查询 */ lookupw_1_arg = word; result_4 = lookupw_1(&lookupw_1_arg, clnt); /* printf("/nYour result is:%d, your string is:%s(%d)/n", *result_4, lookupw_1_arg, strlen(lookupw_1_arg)); */ if (result_4 == (int *) NULL) clnt_perror(clnt, "call failed"); else if(*result_4 ==0) printf("%s found./n", word); else printf("%s not found./n", word); break; case 'q': /* 退出 */ printf("Program quits./n"); exit(0); break; default: /* 非法输入 */ printf("Command %c(%s) invalid./n", cmd, word); break; } /* end of switch */ } /* end of while */ #ifndef DEBUG clnt_destroy(clnt); #endif /* DEBUG */ } int main(int argc, char *argv[]) { char *host; if (argc < 2) { printf("usage: %s server_host/n", argv[0]); exit(1); } host = argv[1]; rdictprog_1(host); exit(0); } |
/* * This is sample code generated by rpcgen. * These are only templates and you can use them * as a guideline for developing your own functions. */ #include "rdict.h" char dict[DICTSIZ][MAXWORD + 1]; /* storage for a dictionary of words */ int nwords = 0; /* number of words in the dictionary */ char init_bool = 0; int initw(void) { if(init_bool) return 1; nwords = 0; init_bool = 1; return 0; } /* end of initw */ /* ------------------------------------------------------------------ * insertw -- insert a word in the dictionary * ------------------------------------------------------------------ */ int insertw(const char *word) { strcpy(dict[nwords%DICTSIZ], word); nwords++; return (nwords); } /* end of insertw */ /* ------------------------------------------------------------------ * deletew -- delete a word from the dictionary * ------------------------------------------------------------------ */ int deletew(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { nwords--; strcpy(dict[i], dict[nwords]); return (1); } } /* end of for */ return (0); } /* end of deletew */ /* ------------------------------------------------------------------ * lookupw -- look up a word in the dictionary * ------------------------------------------------------------------ */ int lookupw(const char *word) { int i; for (i = 0; i < nwords; i++) { if (strcmp(word, dict[i]) == 0) { return 0; } } /* end of for */ return 1; } /* end of lookupw */ int *initw_1_svc(void *argp, struct svc_req *rqstp) { static int result; /* * insert server code here */ result = initw(); return &result; } int *insertw_1_svc(char **argp, struct svc_req *rqstp) { static int result; /* * insert server code here */ result = insertw(*argp); return &result; } int *deletew_1_svc(char **argp, struct svc_req *rqstp) { static int result; /* * insert server code here */ result = deletew(*argp); return &result; } int *lookupw_1_svc(char **argp, struct svc_req *rqstp) { static int result; /* * insert server code here */ result = lookupw(*argp); return &result; } |