Sun RPC的使用

239 篇文章 2 订阅
147 篇文章 1 订阅

Sun RPC的使用

    在分布式系统中,远程过程调用(RPC)是非常重要的通信方式。下面对如何进行RPC程序的编写进行说明。
     Reference:http://www.krzyzanowski.org/rutgers/notes/pdf/ra-sunrpc.pdf
     实现RPC需要写三个文件:IDL语言描述的数据定义,client端程序,server端程序。如图:


    下面举例说明,首先给出本地运行的程序,得到当前时间,并转换为字符串,显示在屏幕上。

stand_alone.c:

#include <stdio.h>

long bin_date(void);
char *str_date(long bintime);

int main(int argc, char **argv)
{
    long lresult; /* return from bin_date */
    char *sresult; /* return from str_date */
    if (argc != 1)
    {
        fprintf(stderr, "usage: %s\n", argv[0]);
        exit(1);
    }
    /* call the procedure bin_date */
    lresult = bin_date();
    printf("time is %ld\n", lresult);
    /* convert the result to a date string */
    sresult = str_date(lresult);
    printf("date is %s", sresult);
    exit(0);
}

/* bin_date returns the system time in binary format */
long bin_date(void)
{
    long timeval;
    long time(); /* Unix time function; returns time */
    timeval = time((long *)0);
    return timeval;
}

/* str_date converts a binary time into a date string */
char *str_date(long bintime)
{
    char *ptr;
    char *ctime(); /* Unix library function that does the work */
    ptr = ctime(&bintime);
    return ptr;
}

    gcc编译此程序并运行:
time is 1270382997
date is Sun Apr 4 20:09:57 2010

    下面将此程序中的两个本地调用函数bin_date和str_date实现为RPC函数。
    首先进行date.x文件的编写,即使用IDL进行函数描述:
date.x:

program DATE_PROG
{
                version DATE_VERS
                {
                                long BIN_DATE(void) = 1;
                                string STR_DATE(long) = 2;
                } = 2;
} = 0x123456;
    其中第7行的“2“是版本号,最后一行的数字是RPC程序ID,不能与系统中其他RPC程序有冲突。写完后使用rpcgen编译此文件(因为上面的version号为2,所以生成的函数都是小写函数名加上"-2-"):
    rpcgen -C date.x
    会得到三个文件:date_clnt.c,date.h,date_svc.c。date.h文件是RPC需要包含的头文件。
    下面开始编写server端程序:
    简单起见,使用rpcgen生成一个server端模板:
    rpcgen -C -Ss date.x >server.c
     生成后的server.c文件内容如下:
server.c:

/*
* 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 "date.h"

long *
bin_date_2_svc(void *argp, struct svc_req *rqstp)
{
        static long result;

        /*
         * insert server code here
         */

        return &result;
}

char **
str_date_2_svc(long *argp, struct svc_req *rqstp)
{
        static char * result;

        /*
         * insert server code here
         */

        return &result;
}
    可见我们只需要进行这两个函数内容的填写即可。因为RPC最终需要将执行结果返回给client端,所以这里的返回值都是指针形式。填写过后的server.c文件如下:
server.c:

/*
* 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 "date.h"

long *
bin_date_2_svc(void *argp, struct svc_req *rqstp)
{
        static long result;
        /*
         * insert server code here
         */
    long time(); /* Unix time function; returns time */
    result = time((long *)0);
        return &result;
}

char **
str_date_2_svc(long *argp, struct svc_req *rqstp)
{
        static char * result;
        /*
         * insert server code here
         */
    char *ctime(); /* Unix library function that does the work */
    result = ctime(argp);
        return &result;
}

    下面开始编写client端程序。client端程序需要包含<rpc/rpc.h>头文件,还需要创建一个CLIENT对象以与server端进行通信。在client端程序运行时加入-h参数指定server端的hostname,默认为localhost。一定要注意RPC调用是可能失败的,如server端没有启动或网络问题等。
client.c:

#include <rpc/rpc.h>
#include "date.h"

int main(int argc, char **argv)
{
    extern char *optarg;
    extern int optind;
    char *server = "localhost";   /* default */
    int err = 0, c;
    while ((c = getopt(argc, argv, "h:")) != -1)
    {
        switch (c)
        {
            case 'h':
                server = optarg;
                break;
            case '?':
                err = 1;
                break;
        }
    }

    /* exit if error or extra arguments */
    if (err || (optind < argc))
    {
        fprintf(stderr, "usage: %s [-h hostname]\n", argv[0]);
        exit(1);
    }

    CLIENT *cl; /* rpc handle */
    cl = clnt_create(server, DATE_PROG, DATE_VERS, "udp");

    long *lresult;
    if ((lresult = bin_date_2(NULL, cl)) == NULL)
    {
        clnt_perror(cl, server); /* failed! */
        exit(1);
    }
    printf("time on %s is %ld\n", server, *lresult);

    char **sresult;
    if ((sresult = str_date_2(lresult, cl)) == NULL)
    {
        /* failed ! */
        clnt_perror(cl, server);
        exit(1);
    }
    printf("date is %s", *sresult);

    clnt_destroy(cl);
    return 0;
}

    至此,RPC程序编写完成,编译过程如下:
    编译client端:gcc -o client client.c date_clnt.c -lnsl
    编译server端:gcc -o server -DRPC_SVC_FG server.c date_svc.c -lnsl
    此处加入RPC_SVC_FG编译参数是为了让server端在前台运行,默认是在后台运行。
    
    编译完毕之后,首先运行server端:
./server
    之后运行client端:
./client
    执行结果如下:
time on localhost is 1270384696
date is Sun Apr 4 20:38:16 2010

    如果在执行server端时出现错误:
Cannot register service: RPC: Unable to receive; errno = Connection refused
    说明系统中没有运行portmap服务,可以通过/etc/init.d/portmap start运行。如果没有安装,debian系LINUX可以通过:

sudo apt-get install portmap
   进行安装。如果没有portmap服务,运行client端可能会Segmentation Fault。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值