Chinaunix首页 | 论坛 | 博客
  • 博客访问: 597232
  • 博文数量: 50
  • 博客积分: 4764
  • 博客等级: 上校
  • 技术积分: 597
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-18 09:00
个人简介

资深IT码农,擅长Linux、C/C++、bash

文章分类

全部博文(50)

文章存档

2015年(17)

2014年(2)

2011年(7)

2010年(4)

2009年(20)

分类: LINUX

2011-08-18 15:13:31

Linux RPC编程的几点体会

Linux下面的RPC模型是SUN RPC (ONC RPC),使用了XDR来编码/解码数据。gcc提供了一些标准数据类型的XDR filter(比如整型,浮点型,字符串等)。对于自定义数据类型,则需要自己编写XDR filter来处理。

你可以使用rpcgen来帮你自动生成xdr filter,但是,该工具需要你提供一个 .x 文件。我在实际使用的过程中,遇到了一些问题,解决问题的过程中有了一些体会。

(1) xdr_string 无法处理C++的string类型,XDR里面的string都是C style的,这点需要注意。

(2) 在C里面,指针可以用来访问数组,但是,在XDR中则不能简单的混为一谈。比如:
有一个数据结构st:
  1. struct st {
  2.     int a;
  3.     int b;
  4. };

  5. struct xxx {
  6.     struct st *buf;
  7.     int c;
  8. };
通过rpcgen生成的 XDR filter 中使用 xdr_pointer,xxx.buf 只能传递一个struct st。如果想要传递一个 struct st 数组,则需要使用 xdr_array(可变size的数组)或 xdr_vector (固定size的数组,与 C++ 标准库里面的vector不是一个概念!),.x文件的写法有些不一样!

(3) 我曾经遇到了一个问题,XDR filter 直接返回失败!通过clnt_perrno得到的错误信息是:Can't encode arguments! 花了很多时间才发现,是因为给数据结构里面的一个string(char *)类型的成员传递了空值,导致xdr_string总是失败!


(4) RPC 传输的数据结构长度有限制,通过UDP方式传输,数据结构长度最大为8K,超过就会失败。如果要传输大的数据结构,可以使用TCP方式。


(5) 曾经遇到一个奇怪的问题,在某台机器上某个rpc调用会出现错误,但是在别的机器上面没有问题,最后发现是因为系统时间是错误的。
我发现,出错的rpc调用是return了系统的时间戳。只要系统的时间在2038年某天以后,rpc就会出错。rpc 调用里面使用了一个long型来传递时间(根据time_t的定义,long型就足够了),系统是64位系统,所以应该没有溢出。我试着将数据类型改为unsigned long。错误消失了。问题的根源没有找到。
下面是测试代码:

date.x:

点击(此处)折叠或打开

  1. program DATE_PROG {
  2.     version DATE_VERS {
  3.         long GET_DATE(void) = 1;
  4.     } = 1;
  5. } = 0x20000002;
date_server.c:
点击(此处)折叠或打开
  1. #include <time.h>
  2. #include "date.h"

  3. long * get_date_1_svc(void *argp, struct svc_req *rqstp)
  4. {
  5.     static long result;

  6.     result = time((long *)0);

  7.     return &result;
  8. }
date_client.c:
点击(此处)折叠或打开
  1. #include "date.h"


  2. void date_prog_1(char *host)
  3. {
  4.     CLIENT *clnt;
  5.     long *result_1;
  6.     char *get_date_1_arg;

  7.     clnt = clnt_create(host, DATE_PROG, DATE_VERS, "udp");
  8.     if (clnt == NULL) {
  9.         clnt_pcreateerror(host);
  10.         exit(1);
  11.     }

  12.     result_1 = get_date_1((void*)&get_date_1_arg, clnt);
  13.     if (result_1 == (long *)NULL) {
  14.         clnt_perror(clnt, "call failed");
  15.         exit(1);
  16.     }
  17.     printf("time on host %s: %ld\n", host, *result_1);

  18.     clnt_destroy(clnt);
  19. }


  20. int main (int argc, char *argv[])
  21. {
  22.     char *host;

  23.     if (argc < 2) {
  24.         printf ("usage: %s server_host\n", argv[0]);
  25.         exit (1);
  26.     }

  27.     host = argv[1];
  28.     date_prog_1(host);
  29.     exit (0);
  30. }
Makefile:
点击(此处)折叠或打开
  1. BIN = server client
  2. GEN = date_clnt.c date_svc.c date_xdr.c date.h
  3. RPCGEN = rpcgen

  4. CFLAGS = -Wall -O -DRPC_SVC_FG #-g
  5. #LDLIBS =
  6. #LDFLAGS =

  7. all: $(BIN)

  8. client: date_client.o date_clnt.o
  9.     $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
  10. server: date_server.o date_svc.o
  11.     $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)

  12. date_client.o: date.h
  13. date_server.o: date.h

  14. $(GEN): date.x
  15.     $(RPCGEN) -C $^
  16. clean:
  17.     $(RM) *.o $(BIN) $(GEN)


阅读(10709) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~