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
可以看到远程的过程已经得到正确的调用了