rpcgen编译器的使用

rpcgen是一个编译器,可以方便的让你写rpc程序,自动生成网络连接的接口代码,免去你手写这些代码的麻烦。也可以说是一个rpc自动代码生成工具。

1. 编写-widebright.x文件,这需要采用“RPC Language”, 就是rpcgen使用的一种语言,和c语言很类似,是“XDR language” 的扩展,关于这个语言的定义和使用自己参考 “rpcgen Programming Guide”了。

------------widebright.x文件内容----------------------------
/*
* widebright.x: Remote widebright protocol. ^_^
*/

/*
* 以百分号开始的行,rpcgen将原封不动的写到输出文件中去
*/
%#define MAX_NAME_LENGTH 64

/*
* XDR语言中数组用尖括号 , 同时char * 要写成 string
*/
struct widebright_info{
unsigned int age;
string name<MAX_NAME_LENGTH>;

};
typedef widebright_info widebright_info_t;


program WIDEBRIGHT_PROG {
     version   WIDEBRIGHT_RPC_VERSION {
             int   GET_AGE(string) = 1;
             string GET_PROFILE(void) = 2;
             widebright_info_t GET_ALL() = 3;
      } = 1;
} = 99;

----------------------------------------------------

2. 执行 “rpcgen widebright.x” 命令
将自动生成如下文件:
widebright.h         定义头文件
widebright_clnt.c       (client side stubs)客户端绑定函数
widebright_svc.c        (server side stubs) 服务器端绑定函数
widebright_xdr.c         XDR 转换函数

---------widebright.h 文件内容-----------------------------------
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/

#ifndef _WIDEBRIGHT_H_RPCGEN
#define _WIDEBRIGHT_H_RPCGEN

#include <rpc/rpc.h>


#ifdef __cplusplus
extern "C" {
#endif

#define MAX_NAME_LENGTH 64

struct widebright_info {
        u_int age;
        char *name;
};
typedef struct widebright_info widebright_info;

typedef widebright_info widebright_info_t;

#define WIDEBRIGHT_PROG 99
#define WIDEBRIGHT_RPC_VERSION 1

#if defined(__STDC__) || defined(__cplusplus)
#define GET_AGE 1
extern int * get_age_1(char **, CLIENT *);
extern int * get_age_1_svc(char **, struct svc_req *);
#define GET_PROFILE 2
extern char ** get_profile_1(void *, CLIENT *);
extern char ** get_profile_1_svc(void *, struct svc_req *);
#define GET_ALL 3
extern widebright_info_t * get_all_1(void *, CLIENT *);
extern widebright_info_t * get_all_1_svc(void *, struct svc_req *);
extern int widebright_prog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);

#else /* K&R C */
#define GET_AGE 1
extern int * get_age_1();
extern int * get_age_1_svc();
#define GET_PROFILE 2
extern char ** get_profile_1();
extern char ** get_profile_1_svc();
#define GET_ALL 3
extern widebright_info_t * get_all_1();
extern widebright_info_t * get_all_1_svc();
extern int widebright_prog_1_freeresult ();
#endif /* K&R C */

/* the xdr functions */

#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_widebright_info (XDR *, widebright_info*);
extern bool_t xdr_widebright_info_t (XDR *, widebright_info_t*);

#else /* K&R C */
extern bool_t xdr_widebright_info ();
extern bool_t xdr_widebright_info_t ();

#endif /* K&R C */

#ifdef __cplusplus
}
#endif

#endif /* !_WIDEBRIGHT_H_RPCGEN */


-----------widebright_clnt.c   文件内容---------------------------------------------
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/

#include <memory.h> /* for memset */
#include "widebright.h"
#define MAX_NAME_LENGTH 64

/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };

int *
get_age_1(char **argp, CLIENT *clnt)
{
        static int clnt_res;

        memset((char *)&clnt_res, 0, sizeof(clnt_res));
        if (clnt_call (clnt, GET_AGE,
                (xdrproc_t) xdr_wrapstring, (caddr_t) argp,
                (xdrproc_t) xdr_int, (caddr_t) &clnt_res,
                TIMEOUT) != RPC_SUCCESS) {
                return (NULL);
        }
        return (&clnt_res);
}

char **
get_profile_1(void *argp, CLIENT *clnt)
{
        static char *clnt_res;

        memset((char *)&clnt_res, 0, sizeof(clnt_res));
        if (clnt_call (clnt, GET_PROFILE,
                (xdrproc_t) xdr_void, (caddr_t) argp,
                (xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
                TIMEOUT) != RPC_SUCCESS) {
                return (NULL);
        }
        return (&clnt_res);
}

widebright_info_t *
get_all_1(void *argp, CLIENT *clnt)
{
        static widebright_info_t clnt_res;

        memset((char *)&clnt_res, 0, sizeof(clnt_res));
        if (clnt_call (clnt, GET_ALL,
                (xdrproc_t) xdr_void, (caddr_t) argp,
                (xdrproc_t) xdr_widebright_info_t, (caddr_t) &clnt_res,
                TIMEOUT) != RPC_SUCCESS) {
                return (NULL);
        }
        return (&clnt_res);
}


-------------widebright_svc.c 文件内容---------------
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/

#include "widebright.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>

#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif
#define MAX_NAME_LENGTH 64

static void
widebright_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
        union {
                char *get_age_1_arg;
        } argument;
        char *result;
        xdrproc_t _xdr_argument, _xdr_result;
        char *(*local)(char *, struct svc_req *);

        switch (rqstp->rq_proc) {
        case NULLPROC:
                (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
                return;

        case GET_AGE:
                _xdr_argument = (xdrproc_t) xdr_wrapstring;
                _xdr_result = (xdrproc_t) xdr_int;
                local = (char *(*)(char *, struct svc_req *)) get_age_1_svc;
                break;

        case GET_PROFILE:
                _xdr_argument = (xdrproc_t) xdr_void;
                _xdr_result = (xdrproc_t) xdr_wrapstring;
                local = (char *(*)(char *, struct svc_req *)) get_profile_1_svc;
                break;

        case GET_ALL:
                _xdr_argument = (xdrproc_t) xdr_void;
                _xdr_result = (xdrproc_t) xdr_widebright_info_t;
                local = (char *(*)(char *, struct svc_req *)) get_all_1_svc;
                break;

        default:
                svcerr_noproc (transp);
                return;
        }
        memset ((char *)&argument, 0, sizeof (argument));
        if (!svc_getargs (transp, _xdr_argument, (caddr_t) &argument)) {
                svcerr_decode (transp);
                return;
        }
        result = (*local)((char *)&argument, rqstp);
        if (result != NULL && !svc_sendreply(transp, _xdr_result, result)) {
                svcerr_systemerr (transp);
        }
        if (!svc_freeargs (transp, _xdr_argument, (caddr_t) &argument)) {
                fprintf (stderr, "%s", "unable to free arguments");
                exit (1);
        }
        return;
}

int
main (int argc, char **argv)
{
        register SVCXPRT *transp;

        pmap_unset (WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION);

        transp = svcudp_create(RPC_ANYSOCK);
        if (transp == NULL) {
                fprintf (stderr, "%s", "cannot create udp service.");
                exit(1);
        }
        if (!svc_register(transp, WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, widebright_prog_1, IPPROTO_UDP)) {
                fprintf (stderr, "%s", "unable to register (WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, udp).");
                exit(1);
        }

        transp = svctcp_create(RPC_ANYSOCK, 0, 0);
        if (transp == NULL) {
                fprintf (stderr, "%s", "cannot create tcp service.");
                exit(1);
        }
        if (!svc_register(transp, WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, widebright_prog_1, IPPROTO_TCP)) {
                fprintf (stderr, "%s", "unable to register (WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, tcp).");
                exit(1);
        }

        svc_run ();
        fprintf (stderr, "%s", "svc_run returned");
        exit (1);
        /* NOTREACHED */
}


-----------widebright_xdr文件内容---------------------------------------
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/

#include "widebright.h"
#define MAX_NAME_LENGTH 64

bool_t
xdr_widebright_info (XDR *xdrs, widebright_info *objp)
{
        register int32_t *buf;

         if (!xdr_u_int (xdrs, &objp->age))
                 return FALSE;
         if (!xdr_string (xdrs, &objp->name, MAX_NAME_LENGTH))
                 return FALSE;
        return TRUE;
}

bool_t
xdr_widebright_info_t (XDR *xdrs, widebright_info_t *objp)
{
        register int32_t *buf;

         if (!xdr_widebright_info (xdrs, objp))
                 return FALSE;
        return TRUE;
}
--------------------------------------------


3.   采用rpcgen的下面这两个选项生成例子程序。
-Sc             generate sample client code that uses remote procedures
-Ss             generate sample server code that defines remote procedures

[widebright@ ddddddd]# rpcgen -Sc -o widebrihgt_client.c widebright.x
[widebright@ ddddddd]# rpcgen -Ss -o widebrihgt_server.c widebright.x

------------widebrihgt_client.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 "widebright.h"
#define MAX_NAME_LENGTH 64


void
widebright_prog_1(char *host)
{
        CLIENT *clnt;
        int *result_1;
        char * get_age_1_arg;
        char * *result_2;
        char *get_profile_1_arg;
        widebright_info_t *result_3;
        char *get_all_1_arg;

#ifndef DEBUG
        clnt = clnt_create (host, WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, "udp");
        if (clnt == NULL) {
                clnt_pcreateerror (host);
                exit (1);
        }
#endif /* DEBUG */

        result_1 = get_age_1(&get_age_1_arg, clnt);
        if (result_1 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        result_2 = get_profile_1((void*)&get_profile_1_arg, clnt);
        if (result_2 == (char **) NULL) {
                clnt_perror (clnt, "call failed");
        }
        result_3 = get_all_1((void*)&get_all_1_arg, clnt);
        if (result_3 == (widebright_info_t *) NULL) {
                clnt_perror (clnt, "call failed");
        }
#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];
        widebright_prog_1 (host);
exit (0);
}

-------------widebrihgt_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 "widebright.h"
#define MAX_NAME_LENGTH 64

int *
get_age_1_svc(char **argp, struct svc_req *rqstp)
{
        static int result;

        /*
         * insert server code here
         */

        return &result;
}

char **
get_profile_1_svc(void *argp, struct svc_req *rqstp)
{
        static char * result;

        /*
         * insert server code here
         */

        return &result;
}

widebright_info_t *
get_all_1_svc(void *argp, struct svc_req *rqstp)
{
        static widebright_info_t result;

        /*
         * insert server code here
         */

        return &result;
}


4.
修改widebrihgt_client.c 和widebrihgt_server.c 文件,补全服务器端和客户端调用的代码。
可以参考 “Remote Procedure Call Programming Guide” 的说明

--------修改后的widebrihgt_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 <stdlib.h>
#include "widebright.h"
#define MAX_NAME_LENGTH 64

char   widebright_descriptions[256]="widebright is a good boy ^_^";
char name []="widebright";
int *
get_age_1_svc(char **name, struct svc_req *rqstp)
{
        static int age;

        /*
         * insert server code here
         */
        if ( 0 == strcmp ( *name, "widebright"))
        {
            age =24;
       }else {
             age =0;
        }


        return &age;
}

char **
get_profile_1_svc(void *argp, struct svc_req *rqstp)
{
        static char * description;
        /*
         * insert server code here
         */
       description = widebright_descriptions ;
        return &description;
}

widebright_info_t *
get_all_1_svc(void *argp, struct svc_req *rqstp)
{
        static widebright_info_t info;

        /*
         * insert server code here
         */

         info.age = 24;
         info.name =name;
/*
         printf ("name length=%d",strlen(info.name));
         strcpy (info.name , "widebright");
*/

   return &info;
}

------------修改后的widebrihgt_client.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 <stdio.h>
#include "widebright.h"
#define MAX_NAME_LENGTH 64


void
widebright_prog_1(char *host)
{
        CLIENT *clnt;
        int *result_1;
        char * get_age_1_arg;
        char name [256] ="widebright";
        char name2 [256] ="unkown";
        char * *result_2;
        char *get_profile_1_arg;
        widebright_info_t *result_3;
        char *get_all_1_arg;

#ifndef DEBUG
        clnt = clnt_create (host, WIDEBRIGHT_PROG, WIDEBRIGHT_RPC_VERSION, "udp");
        if (clnt == NULL) {
                clnt_pcreateerror (host);
                exit (1);
        }
#endif /* DEBUG */

      get_age_1_arg   = name ;
        result_1 = get_age_1( &get_age_1_arg, clnt);
        if (result_1 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        printf ("%s 's age is %d.\n" , name,*result_1 );

       get_age_1_arg   = name2 ;
        result_1 = get_age_1(&get_age_1_arg, clnt);
        if (result_1 == (int *) NULL) {
                clnt_perror (clnt, "call failed");
        }
        printf ("%s 's age is %d.\n" , name2,*result_1 );


        result_2 = get_profile_1((void*)&get_profile_1_arg, clnt);
        if (result_2 == (char **) NULL) {
                clnt_perror (clnt, "call failed");
        }

        printf ("widebright's description:%s\n" , *result_2 );


        result_3 = get_all_1((void*)&get_all_1_arg, clnt);
        if (result_3 == (widebright_info_t *) NULL) {
                clnt_perror (clnt, "call failed");
        }

       printf ("widebright's age:%d\n" ,   (*result_3).age );
       printf ("widebright's name:%s\n" ,   (*result_3).name );

#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];
        widebright_prog_1 (host);
exit (0);
}

-------------------------------------------------------------------------------


5.
编译生成服务器端程序 ,
gcc widebright_xdr.c widebright_svc.c widebrihgt_server.c -o widebrihgt_server
编译生成客户端程序
gcc widebright_clnt.c widebright_xdr.c widebrihgt_client.c -o widebrihgt_client


然后用scp命令复制widebrihgt_server到远程机器上运行
[widebright ddddddd]# ./widebrihgt_server &
[1] 11531

然后在本地运行客户机widebrihgt_client 去连接远程程序,这里是连接本地机器上的
[widebright ddddddd]# ./widebrihgt_client 127.0.0.1
widebright 's age is 24.
unkown 's age is 0.
widebright's description:widebright is a good boy ^_^
widebright's age:24
widebright's name:widebright


可以看到远程的过程已经得到正确的调用了

rpcgen是一个远程过程调用(RPC)协议编译器,它可以生成客户端和服务器端程序代码,用于实现跨网络的程序通信。下面是一个简单的rpcgen例子程序: ``` /* message.x - RPC协议文件 */ struct message { int id; string text<200>; }; program MESSAGEPROG { version MESSAGEVERS { message MESSAGEPROC(int) = 1; } = 1; } = 0x31230000; /* 用于标识RPC协议的唯一值 */ ``` 上面的代码定义了一个名为MESSAGEPROG的RPC程序,包含一个版本MESSAGEVERS,其中有一个名为MESSAGEPROC的过程。过程接受一个整数作为参数,并返回一个消息结构体。现在我们使用rpcgen来编译这个协议文件,生成客户端和服务器端的代码: ``` rpcgen message.x ``` 这将生成四个文件:message.h、message_clnt.c、message_svc.c、message_xdr.c。其中,message.h包含了协议的数据类型定义和函数声明,message_clnt.c是客户端程序的代码,message_svc.c是服务器端程序的代码,message_xdr.c是帮助程序将数据转换为网络字节序的代码。 下面是一个简单的服务器端程序代码示例: ``` #include "message.h" #include <stdio.h> #include <stdlib.h> message * messageproc_1_svc(int *id, struct svc_req *rqstp) { static message result; result.id = *id; sprintf(result.text, "Hello, client %d!", *id); return &result; } int main(int argc, char **argv) { register SVCXPRT *transp; /* 创建TCP连接 */ transp = svc_tcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf(stderr, "cannot create TCP service.\n"); exit(1); } /* 注册服务程序 */ if (!svc_register(transp, MESSAGEPROG, MESSAGEVERS, messageprog_1, IPPROTO_TCP)) { fprintf(stderr, "unable to register (MESSAGEPROG, MESSAGEVERS, tcp).\n"); exit(1); } /* 运行RPC服务 */ svc_run(); fprintf(stderr, "unable to run RPC service.\n"); exit(1); } ``` 上面的代码实现了MESSAGEPROC过程的服务端代码,该过程接受一个整数作为参数,返回一个包含问候信息的message结构体。函数注册和运行部分使用rpc库提供的函数。 下面是一个简单的客户端程序代码示例: ``` #include "message.h" #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { CLIENT *cl; message *result; int *id; /* 创建RPC客户端 */ cl = clnt_create(argv[1], MESSAGEPROG, MESSAGEVERS, "tcp"); if (cl == NULL) { fprintf(stderr, "cannot create RPC client.\n"); exit(1); } /* 发送RPC请求 */ id = (int *) malloc(sizeof(int)); *id = atoi(argv[2]); result = messageproc_1(id, cl); if (result == NULL) { fprintf(stderr, "RPC error: %s\n", clnt_sperror(cl, argv[1])); exit(1); } /* 处理RPC响应 */ printf("%s\n", result->text); /* 释放资源 */ clnt_destroy(cl); free(id); exit(0); } ``` 上面的代码实现了MESSAGEPROC过程的客户端代码,该过程接受一个整数作为参数,发送RPC请求到服务器端,接收并输出服务器端返回的问候信息。需要注意的是,程序需要接受命令行参数,分别为服务器端的IP地址和一个整数作为ID参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值