linux下的RPC编程,关于RPC的协议以及工作原理这里就不说了,没了解的可以先网上查找了解下,下面就一个简单例子来说明RPC,例子是这样的:客户端向服务器端发出命令,然后服务端回应相应的数据。
1 #define MAXLEN 1500 2 #define RPC_HELLO 0x80000088 3 enum type { 4 rpc_invalid, 5 rpc_hello, 6 rpc_goodbye, 7 rpc_number 8 }; 9 10 struct _hello_t { 11 enum type op; 12 int status; 13 char data[MAXLEN]; 14 }; 15 16 typedef struct _hello_t hello_t; 17 18 program helloProg { 19 version helloVers { 20 hello_t rpc_hello( hello_t ) = 1; 21 } = 1; 22 } = RPC_HELLO;
编写了hello.x文件,上面可以看到RPC由程序号(program number),程序版本号(program version number),过程号(procedure number)唯一确定的。hello_t rpc_hello ( hello_t ) 就是我们定义的接口,
定义好后,在linux利用rpc解析工具rpcgen对.x文件进行处理得到想要的文件,如下
dgq@t468 rpc $ ls hello.x dgq@t468 rpc $ rpcgen hello.x dgq@t468 rpc $ ls hello.h hello.x hello_clnt.c hello_svc.c hello_xdr.c dgq@t468 rpc $ rpcgen -Sc -o hello_client.c hello.x dgq@t468 rpc $ rpcgen -Ss -o hello_server.c hello.x dgq@t468 rpc $ rpcgen -Sm hello.x > Makefile dgq@t468 rpc $ ls Makefile hello.h hello.x hello_client.c hello_clnt.c hello_server.c hello_svc.c hello_xdr.c
生成的这些文件,主要关注hello_client.c hello_server.c,内容如下
hello_client.c
1 /* 2 * This is sample code generated by rpcgen. 3 * These are only templates and you can use them 4 * as a guideline for developing your own functions. 5 */ 6 7 #include "hello.h" 8 9 10 void 11 helloprog_1(char *host) 12 { 13 CLIENT *clnt; 14 hello_t *result_1; 15 hello_t rpc_hello_1_arg; 16 17 #ifndef DEBUG 18 clnt = clnt_create (host, helloProg, helloVers, "udp"); 19 if (clnt == NULL) { 20 clnt_pcreateerror (host); 21 exit (1); 22 } 23 #endif /* DEBUG */ 24 25 result_1 = rpc_hello_1(&rpc_hello_1_arg, clnt); 26 if (result_1 == (hello_t *) NULL) { 27 clnt_perror (clnt, "call failed"); 28 } 29 #ifndef DEBUG 30 clnt_destroy (clnt); 31 #endif /* DEBUG */ 32 } 33 34 35 int 36 main (int argc, char *argv[]) 37 { 38 char *host; 39 40 if (argc < 2) { 41 printf ("usage: %s server_host\n", argv[0]); 42 exit (1); 43 } 44 host = argv[1]; 45 helloprog_1 (host); 46 exit (0); 47 }
hello_server.c
1 /* 2 * This is sample code generated by rpcgen. 3 * These are only templates and you can use them 4 * as a guideline for developing your own functions. 5 */ 6 7 #include "hello.h" 8 9 hello_t * 10 rpc_hello_1_svc(hello_t *argp, struct svc_req *rqstp) 11 { 12 static hello_t result; 13 14 /* 15 * insert server code here 16 */ 17 18 return &result; 19 } ~ ~
然后对这两个文件进行修改后,如下
1 /* 2 * This is sample code generated by rpcgen. 3 * These are only templates and you can use them 4 * as a guideline for developing your own functions. 5 */ 6 7 #include "hello.h" 8 #include <string.h> 9 #include <stdlib.h> 10 11 void 12 helloprog_1(char *host, int flag) 13 { 14 CLIENT *clnt; 15 hello_t *result_1; 16 hello_t data; 17 18 bzero(&data, sizeof data); 19 #ifndef DEBUG 20 clnt = clnt_create (host, helloProg, helloVers, "udp"); 21 if (clnt == NULL) { 22 clnt_pcreateerror (host); 23 exit (1); 24 } 25 #endif /* DEBUG */ 26 27 if (flag == 1){ 28 data.op = rpc_hello; 29 } 30 if (flag == 2){ 31 data.op = rpc_goodbye; 32 } 33 result_1 = rpc_hello_1(&data, clnt); 34 if (result_1 == (hello_t *) NULL) { 35 clnt_perror (clnt, "call failed"); 36 } 37 printf("%s", result_1->data); 38 39 #ifndef DEBUG 40 clnt_destroy (clnt); 41 #endif /* DEBUG */ 42 } 43 44 45 int 46 main (int argc, char *argv[]) 47 { 48 char *host; 49 int flag; 50 if (argc < 3) { 51 printf ("usage: %s server_host\n", argv[0]); 52 exit (1); 53 } 54 host = argv[1]; 55 flag = atoi(argv[2]); 56 helloprog_1 (host, flag); 57 exit (0); 58 59 }
1 #include "hello.h" 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <time.h> 5 6 hello_t * 7 rpc_hello_1_svc(hello_t *argp, struct svc_req *rqstp) 8 { 9 static hello_t result; 10 11 struct timeval tv; 12 13 gettimeofday(&tv, NULL); 14 15 16 /* 17 * insert server code here 18 */ 19 switch(argp->op){ 20 case 1: 21 sprintf(result.data, "%s:Hello 2013!\n%s", getenv("USER"), ctime(&tv.tv_sec)); 22 break; 23 case 2: 24 sprintf(result.data, "%s:Goodbye 2012!\n%s", getenv("USER"), ctime(&tv.tv_sec)); 25 break; 26 default: 27 sprintf(result.data, "unkown commond!\n"); 28 } 29 30 return &result; 31 }
然后对Makefile进行修改,如下
1 # This is a template Makefile generated by rpcgen 2 3 # Parameters 4 5 CLIENT = hello_client 6 SERVER = hello_server 7 8 SOURCES_CLNT.c = 9 SOURCES_CLNT.h = 10 SOURCES_SVC.c = 11 SOURCES_SVC.h = 12 SOURCES.x = hello.x 13 14 TARGETS_SVC.c = hello_svc.c hello_xdr.c hello_server.c 15 TARGETS_CLNT.c = hello_clnt.c hello_xdr.c hello_client.c 16 TARGETS = hello.h hello_xdr.c hello_clnt.c hello_svc.c 17 18 OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o) 19 OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o) 20 # Compiler flags 21 22 CFLAGS += -g 23 LDLIBS += -lnsl 24 RPCGENFLAGS = 25 26 # Targets 27 28 all : $(CLIENT) $(SERVER) 29 30 $(TARGETS) : $(SOURCES.x) 31 rpcgen $(RPCGENFLAGS) $(SOURCES.x) 32 33 $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c)
然后make就会产生可执行文件,hello_client 和 hello_server, 启动hello_server作为后台运行,运行hello_client 等到结果如下:
root@t468 rpc # ./hello_server & [1] 28379 root@t468 rpc # ./hello_client 127.0.0.1 1 root:Hello 2013! Sun Jan 13 13:24:58 2013 root@t468 rpc # ./hello_client 127.0.0.1 2 root:Goodbye 2012! Sun Jan 13 13:25:00 2013 root@t468 rpc #
这里把客户端和服务端都运行在同一台机子上,使用回环地址来请求,可以看到能正常工作,但在实际项目中没有这么简单,比如对timeout,用udp还是tcp都有要求,不过掌握了基本的,也复杂不到哪里去。