#define MY_RPC_PROG_NUM 0x38000010 //程序號
struct my_io_data_s //定義消息結構
{
int mtype;
int len;
char data[1024];
};
typedef struct my_io_data_s my_io_data_t;
program MY_RPC_PROG {
version MY_RPC_VERS1 {
int MY_RPCC(my_io_data_t) = 1; /* 過程號 = 1 */
} = 1; /* Version number = 1 */
version MY_RPC_VERS2 {
my_io_data_t MY_RPCC(my_io_data_t) = 1; /* 過稱號 = 1 */
} = 2; /* Version number = 2 */
} = MY_RPC_PROG_NUM; /* Program number */
這裡我創建了兩個版本,version1和version2,版本的數量是可以自己定制的,如果你需要一個的話定義一個即可。因為我打算定義一個版本用於SET的操作,一個用於GET操作,所以定義了兩個版本。
上面使用了RPC語言,我對以上幾個特殊名詞做一下解釋。
每個RPC過程由程序號、版本號和過程號來唯一確定。
RPC版本號:程序號標志一組相關的遠程過程,程序號的是有范圍的,我們需要在范圍內填寫程序號。
程序號范圍
簡述
0x00000000 - 0x1FFFFFFF
由Sun公司定義,提供特定服務
0x20000000 - 0x3FFFFFFF
由程序員自己定義,提供本地服務或用於調試
0x40000000 - 0x5FFFFFFF
用於短時間使用的程序,例如回調程序
0x60000000 - 0xFFFFFFFF
保留程序號
這裡我們使用的范圍當然是0x20000000 - 0x3FFFFFFF,我填的是0x38000010。
版本號:在version的大括號裡我們定義兩個我們將要使用的RPC調用函數的類型,比如:
version 1:我們定義了int MY_RPCC(my_io_data_t),這表明我們以後PRC框架使用的RPC調用函數的函數類型那個將會是:int * my_rpcc_1(my_io_data_t *argp, CLIENT *clnt)
version 2:my_io_data_t MY_RPCC(my_io_data_t) 則會變成 my_io_data_t * my_rpcc_2(my_io_data_t *argp, CLIENT *clnt)
所以我們可以根據我們需要的類型模仿編寫即可。
2.使用rpcgen指令生成以下幾個文件
使用rpcgen my.x生成系列文件(可以加參數-C,表示使用ANSI C)
執行該指令後,文件夾下將出現以下幾個文件。
my.h:

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _MY_H_RPCGEN
#define _MY_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct my_io_data_s {
int mtype;
int len;
char data[1024];
};
typedef struct my_io_data_s my_io_data_s;
typedef my_io_data_s my_io_data_t;
#define MY_RPC_PROG 666
#define MY_RPC_VERS1 1
#if defined(__STDC__) || defined(__cplusplus)
#define MY_RPCC 1
extern int * my_rpcc_1(my_io_data_t *, CLIENT *);
extern int * my_rpcc_1_svc(my_io_data_t *, struct svc_req *);
extern int my_rpc_prog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define MY_RPCC 1
extern int * my_rpcc_1();
extern int * my_rpcc_1_svc();
extern int my_rpc_prog_1_freeresult ();
#endif /* K&R C */
#define MY_RPC_VERS2 2
#if defined(__STDC__) || defined(__cplusplus)
extern my_io_data_t * my_rpcc_2(my_io_data_t *, CLIENT *);
extern my_io_data_t * my_rpcc_2_svc(my_io_data_t *, struct svc_req *);
extern int my_rpc_prog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
extern my_io_data_t * my_rpcc_2();
extern my_io_data_t * my_rpcc_2_svc();
extern int my_rpc_prog_2_freeresult ();
#endif /* K&R C */
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_my_io_data_s (XDR *, my_io_data_s*);
extern bool_t xdr_my_io_data_t (XDR *, my_io_data_t*);
#else /* K&R C */
extern bool_t xdr_my_io_data_s ();
extern bool_t xdr_my_io_data_t ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_MY_H_RPCGEN */
View Code
my_clnt.c:

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include <memory.h> /* for memset */
#include "my.h"
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };
int *
my_rpcc_1(my_io_data_t *argp, CLIENT *clnt)
{
static int clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, MY_RPCC,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) argp,
(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
my_io_data_t *
my_rpcc_2(my_io_data_t *argp, CLIENT *clnt)
{
static my_io_data_t clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, MY_RPCC,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) argp,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
View Code
my_svc.c

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "my.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
static void
my_rpc_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
my_io_data_t my_rpcc_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 MY_RPCC:
_xdr_argument = (xdrproc_t) xdr_my_io_data_t;
_xdr_result = (xdrproc_t) xdr_int;
local = (char *(*)(char *, struct svc_req *)) my_rpcc_1_svc;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
return;
}
static void
my_rpc_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
my_io_data_t my_rpcc_2_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 MY_RPCC:
_xdr_argument = (xdrproc_t) xdr_my_io_data_t;
_xdr_result = (xdrproc_t) xdr_my_io_data_t;
local = (char *(*)(char *, struct svc_req *)) my_rpcc_2_svc;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _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 (MY_RPC_PROG, MY_RPC_VERS1);
pmap_unset (MY_RPC_PROG, MY_RPC_VERS2);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, MY_RPC_PROG, MY_RPC_VERS1, my_rpc_prog_1, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (MY_RPC_PROG, MY_RPC_VERS1, udp).");
exit(1);
}
if (!svc_register(transp, MY_RPC_PROG, MY_RPC_VERS2, my_rpc_prog_2, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (MY_RPC_PROG, MY_RPC_VERS2, 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, MY_RPC_PROG, MY_RPC_VERS1, my_rpc_prog_1, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (MY_RPC_PROG, MY_RPC_VERS1, tcp).");
exit(1);
}
if (!svc_register(transp, MY_RPC_PROG, MY_RPC_VERS2, my_rpc_prog_2, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (MY_RPC_PROG, MY_RPC_VERS2, tcp).");
exit(1);
}
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}
View Code
my_xdr.c

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "my.h"
bool_t
xdr_my_io_data_s (XDR *xdrs, my_io_data_s *objp)
{
register int32_t *buf;
int i;
if (!xdr_int (xdrs, &objp->mtype))
return FALSE;
if (!xdr_int (xdrs, &objp->len))
return FALSE;
if (!xdr_vector (xdrs, (char *)objp->data, 1024,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
return TRUE;
}
bool_t
xdr_my_io_data_t (XDR *xdrs, my_io_data_t *objp)
{
register int32_t *buf;
if (!xdr_my_io_data_s (xdrs, objp))
return FALSE;
return TRUE;
}
View Code
3.rpcgen -Sc -o my_client.c my.x 生成my_client.c 使用該指令後我們就生成了客戶端.c文件,這個文件很重要,因為以後我們做業務開發就在這裡做,我們的調用都會從這裡開始。 my_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 "my.h"
void
my_rpc_prog_1(char *host)
{
CLIENT *clnt;
int *result_1;
my_io_data_t my_rpcc_1_arg;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS1, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = my_rpcc_1(&my_rpcc_1_arg, clnt);
if (result_1 == (int *) NULL) {
clnt_perror (clnt, "call failed");
}
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
}
void
my_rpc_prog_2(char *host)
{
CLIENT *clnt;
my_io_data_t *result_1;
my_io_data_t my_rpcc_2_arg;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS2, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = my_rpcc_2(&my_rpcc_2_arg, clnt);
if (result_1 == (my_io_data_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];
my_rpc_prog_1 (host);
my_rpc_prog_2 (host);
exit (0);
}
View Code
現在我們就可以在該文件編寫客戶端的代碼了。
5.rpcgen -Ss -o my_server.c my.x生成文件my_server.c
使用該指令後我們就生成了服務器.c文件,這個文件很重要,因為以後我們做業務開發就在這裡做,我們將在這裡編寫處理客戶端請求的代碼。
my_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 "my.h"
int *
my_rpcc_1_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static int result;
/*
* insert server code here
*/
return &result;
}
my_io_data_t *
my_rpcc_2_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static my_io_data_t result;
/*
* insert server code here
*/
return &result;
}
View Code
6.在my_server.c和my_client.c添加測試代碼 所有利用rpcgen生成的文件都已經生成完畢,接下來我們需要添加測試代碼來驗證該RPC骨架是否正常工作。 my_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 "my.h"
void
my_rpc_prog_1(char *host)
{
CLIENT *clnt;
int *result_1;
my_io_data_t my_rpcc_1_arg;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS1, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = my_rpcc_1(&my_rpcc_1_arg, clnt);
if (result_1 == (int *) NULL) {
clnt_perror (clnt, "call failed");
}
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
}
void
my_rpc_prog_2(char *host)
{
CLIENT *clnt;
my_io_data_t *result_1;
my_io_data_t my_rpcc_2_arg;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS2, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
my_rpcc_2_arg.mtype = 3;
my_rpcc_2_arg.len = 18;
result_1 = my_rpcc_2(&my_rpcc_2_arg, clnt);
if (result_1 == (my_io_data_t *) NULL) {
clnt_perror (clnt, "call failed");
}
fprintf(stderr,"recv msg from server! mtype:%d len:%d \n",result_1->mtype,result_1->len);
#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];
//my_rpc_prog_1 (host);
my_rpc_prog_2 (host);
exit (0);
}
View Code
值得注意的是,我們client使用的是UDP協議,當然我們用戶也可以根據自己需要選用TCP協議進行開發。
my_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 "my.h"
int *
my_rpcc_1_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static int result;
/*
* insert server code here
*/
return &result;
}
my_io_data_t *
my_rpcc_2_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static my_io_data_t result;
/*
* insert server code here
*/
printf("recv msg from client! len:%d, mt:%d \n",argp->len,argp->mtype);
result.mtype = 33;
result.len = 12;
return &result;
}
View Code
7.測試現象
編譯這client和server
gcc -o client my_clnt.c my_client.c my_xdr.c
gcc -o server my_svc.c my_server.c my_xdr.c
我在主機172.0.5.183運行server程序,在172.0.5.183運行client程序,測試現象如下:
server端
client端

typedef struct my_msg_hdr_s
{
int mtype;
int len;
}my_msg_hdr_t;
typedef struct my_msg_s
{
my_msg_hdr_t msg_hdr;
int para1;
int para2;
int result;
}my_msg_t;
然後我們先改變一下我們的客戶端程序,
my_rpc_prog_1主要負責服務器的設置,比如在該程序裡,此函數就用於設置服務器的開關,所以這個函數只需要把消息發給服務器端就可以了,不需要服務器返回數據給它,所以使用了int的返回值。
而my_rpc_prog_2則需要給它返回數據結果的,所以該函數使用了my_io_data_t *作返回值。
/*
* 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 "my.h"
#include "rpc_msg.h"
int my_rpc_prog_1(char *host, my_io_data_t* in_msg)
{
CLIENT *clnt;
int *result_1;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS1, "udp");
if (clnt == NULL)
{
printf("Fail to create rpc client1!\n");
return -1;
}
#endif /* DEBUG */
result_1 = my_rpcc_1(in_msg, clnt);
if (result_1 == (int *) NULL)
{
clnt_perror (clnt, "call failed");
return -1;
}
return 0;
}
my_io_data_t * my_rpc_prog_2(char *host, my_io_data_t* in_msg)
{
CLIENT *clnt;
my_io_data_t *result_1 = NULL;
#ifndef DEBUG
clnt = clnt_create (host, MY_RPC_PROG, MY_RPC_VERS2, "udp");
if (clnt == NULL)
{
printf("Fail to create rpc client1!\n");
return NULL;
}
#endif /* DEBUG */
result_1 = my_rpcc_2(in_msg, clnt);
if (result_1 == (my_io_data_t *) NULL)
{
clnt_perror (clnt, "call failed");
return NULL;
}
return result_1;
}
void get_compute_result(char *host, int type, int para1, int para2)
{
my_io_data_t in_msg;
my_msg_t* rsp;
my_io_data_t* out_msg;
my_msg_t* req = (my_msg_t*)&in_msg;
memset(&in_msg, 0, sizeof(in_msg));
req->msg_hdr.mtype = type;
req->msg_hdr.len = sizeof(in_msg) - sizeof(my_msg_hdr_t);
req->para1 = para1;
req->para2 = para2;
out_msg = my_rpc_prog_2(host, &in_msg);
rsp = (my_msg_t*)out_msg;
if(rsp == NULL)
{
printf("RPC call fail!\n");
return;
}
printf("compute result is %d\n",rsp->result);
}
void server_switch(char *host, int type)
{
my_io_data_t msg;
my_msg_t* in_msg = (my_msg_t*)&msg;
memset(&msg, 0, sizeof(msg));
in_msg->msg_hdr.mtype = type;
in_msg->msg_hdr.len = sizeof(msg) - sizeof(my_msg_hdr_t);
if(my_rpc_prog_1(host, &msg))
{
printf("enable server fail!\n");
}
printf("Configure server successfully!\n");
}
int main (int argc, char *argv[])
{
server_switch(SERVER_IP, RPC_enable); //server start
sleep(1);
get_compute_result(SERVER_IP, RPC_ADD, 6, 3);
sleep(1);
get_compute_result(SERVER_IP, RPC_SUB, 6, 3);
sleep(1);
get_compute_result(SERVER_IP, RPC_MUL, 6, 3);
sleep(1);
get_compute_result(SERVER_IP, RPC_DIV, 6, 3);
sleep(1);
server_switch(SERVER_IP, RPC_disable); //server close
return 0;
}
當然改了以上的兩個函數,我們當然也需要在my_clnt.c和my.h作出函數聲明的修改。
現在看看server端怎麼處理這些請求的。
my_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 "my.h"
#include "rpc_msg.h"
int* my_rpcc_1_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static int result;
switch(argp->mtype)
{
case RPC_enable:
printf("server start!\n");
break;
case RPC_disable:
printf("server close!\n");
break;
default:
break;
}
return &result;
}
my_io_data_t* my_rpcc_2_svc(my_io_data_t *argp, struct svc_req *rqstp)
{
static my_io_data_t result;
my_msg_t* out = (my_msg_t*)&result;
my_msg_t* in = (my_msg_t*)argp;
switch(in->msg_hdr.mtype)
{
case RPC_ADD:
out->result = in->para1 + in->para2;
break;
case RPC_SUB:
out->result = in->para1 - in->para2;
break;
case RPC_MUL:
out->result = in->para1 * in->para2;
break;
case RPC_DIV:
out->result = in->para1/in->para2;
break;
default:
break;
}
return &result;
}
附上有修改的文件 rpc_msg.h

#define SERVER_IP "172.0.5.183"
enum RPC_REQ_TYPE_1
{
RPC_enable,
RPC_disable,
};
enum RPC_REQ_TYPE_2
{
RPC_ADD,
RPC_SUB,
RPC_MUL,
RPC_DIV,
};
typedef struct my_msg_hdr_s
{
int mtype;
int len;
}my_msg_hdr_t;
typedef struct my_msg_s
{
my_msg_hdr_t msg_hdr;
int para1;
int para2;
int result;
}my_msg_t;
View Code
my_clnt.c:

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include <memory.h> /* for memset */
#include "my.h"
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };
int *
my_rpcc_1(my_io_data_t *argp, CLIENT *clnt)
{
static int clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, MY_RPCC,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) argp,
(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
my_io_data_t *
my_rpcc_2(my_io_data_t *argp, CLIENT *clnt)
{
static my_io_data_t clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, MY_RPCC,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) argp,
(xdrproc_t) xdr_my_io_data_t, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
View Code
my.h

/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _MY_H_RPCGEN
#define _MY_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct my_io_data_s {
int mtype;
int len;
char data[1024];
};
typedef struct my_io_data_s my_io_data_s;
typedef my_io_data_s my_io_data_t;
#define MY_RPC_PROG 666
#define MY_RPC_VERS1 1
#if defined(__STDC__) || defined(__cplusplus)
#define MY_RPCC 1
extern int * my_rpcc_1(my_io_data_t *, CLIENT *);
extern int * my_rpcc_1_svc(my_io_data_t *, struct svc_req *);
extern int my_rpc_prog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define MY_RPCC 1
extern int * my_rpcc_1();
extern int * my_rpcc_1_svc();
extern int my_rpc_prog_1_freeresult ();
#endif /* K&R C */
#define MY_RPC_VERS2 2
#if defined(__STDC__) || defined(__cplusplus)
extern my_io_data_t * my_rpcc_2(my_io_data_t *, CLIENT *);
extern my_io_data_t * my_rpcc_2_svc(my_io_data_t *, struct svc_req *);
extern int my_rpc_prog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
extern my_io_data_t * my_rpcc_2();
extern my_io_data_t * my_rpcc_2_svc();
extern int my_rpc_prog_2_freeresult ();
#endif /* K&R C */
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_my_io_data_s (XDR *, my_io_data_s*);
extern bool_t xdr_my_io_data_t (XDR *, my_io_data_t*);
#else /* K&R C */
extern bool_t xdr_my_io_data_s ();
extern bool_t xdr_my_io_data_t ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_MY_H_RPCGEN */
View Code
實驗結果: 編譯這client和server gcc -o client my_clnt.c my_client.c my_xdr.c gcc -o server my_svc.c my_server.c my_xdr.c 首先在主機172.0.5.183上運行server程序,然後在主機172.0.5.182運行client程序 同時觀察兩個主機的輸出情況:

http://xxxxxx/Linuxjc/1191671.html TechArticle