利用tirpc庫實現簡單的客戶端和服務端
來源 https://www.hlovefp.cn/blog/post/125.html
演示系統:openEuler release 22.03 LTS
1. 準備環境
Bash
yum install rpcgen -y # rpcgen命令
yum -y install libtirpc libtirpc-devel # rpc庫
一個RPC程式通常包括(每個RPC過程由程式設計師、版本號和過程號唯一標誌):
程式號
版本號
過程號
網路選擇 傳輸協議,主要是udp或tcp
rpcbind服務 rpcbind是用來連線網路服務和透過網路地址的基礎服務,一般使用埠號111。
外部資料表示XDR 在RPC客戶機方和伺服器方之間傳送的資料按XDR傳輸語法編碼。
2. 生成XDR檔案
RPC使用XDR標準傳送資料,參考:https://www.hlovefp.cn/blog/post/124.html
Bash
[root@localhost rpc]# cat request.x # request.x 定義的客戶端伺服器資料結構
struct calculator {
int op;
float arg1;
float arg2;
float result;
};
[root@localhost rpc]# rpcgen request.x # 生成 request.h 和 request_xdr.c
C
[root@localhost rpc]# cat request.h
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _REQUEST_H_RPCGEN
#define _REQUEST_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct calculator {
int op;
float arg1;
float arg2;
float result;
};
typedef struct calculator calculator;
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_calculator (XDR *, calculator*);
#else /* K&R C */
extern bool_t xdr_calculator ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_REQUEST_H_RPCGEN */
Bash
[root@localhost rpc]# cat request_xdr.c
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "request.h"
bool_t
xdr_calculator (XDR *xdrs, calculator *objp)
{
register int32_t *buf;
if (!xdr_int (xdrs, &objp->op))
return FALSE;
if (!xdr_float (xdrs, &objp->arg1))
return FALSE;
if (!xdr_float (xdrs, &objp->arg2))
return FALSE;
if (!xdr_float (xdrs, &objp->result))
return FALSE;
return TRUE;
}
3. 服務端程式碼
C
#include <stdio.h>
#include <string.h>
#include <rpc/auth.h>
#include <rpc/svc.h>
#include "request.h"
#define CALCULATOR_PROG ((unsigned long)0x20000001)
#define CALCULATOR_VER ((unsigned long)0x1)
#define CALCULATOR_PROC ((unsigned long)0x1)
#define CALCULATOR_ADD 0
#define CALCULATOR_SUB 1
#define CALCULATOR_MUL 2
#define CALCULATOR_DIV 3
void handle_calculator(struct svc_req *req, SVCXPRT *xprt)
{
calculator c;
memset(&c, 0x00, sizeof(c));
// 獲取資料
if (!svc_getargs(xprt, (xdrproc_t)xdr_calculator, (caddr_t)&c)) {
printf("error: svc_getargs error.\n");
svcerr_decode(xprt);
return;
}
switch(c.op) {
case CALCULATOR_ADD:
c.result = c.arg1 + c.arg2;
break;
case CALCULATOR_SUB:
c.result = c.arg1 - c.arg2;
break;
case CALCULATOR_MUL:
c.result = c.arg1 * c.arg2;
break;
case CALCULATOR_DIV:
if (c.arg2 != 0) {
c.result = c.arg1 / c.arg2;
}
break;
default:
break;
}
if(!svc_sendreply(xprt, (xdrproc_t)xdr_calculator, (caddr_t)&c)) {
printf("error: svc_sendreply error.\n");
}
if(!svc_freeargs(xprt, (xdrproc_t)xdr_calculator, (caddr_t)&c)) {
printf("error: svc_freeargs error.\n");
}
}
void dispatch_handle(struct svc_req *req, SVCXPRT *xprt)
{
printf("rq_prog : %d service program number\n", req->rq_prog);
printf("rq_vers : %d service protocol version\n", req->rq_vers);
printf("rq_proc : %d the desired procedure\n", req->rq_proc);
// 當伺服器得到客戶機請求的結構時,伺服器程式需要呼叫函式svc_sendreply向客戶機傳送報文。
// bool_t svc_sendreply(SVCXPRT *xprt, xdrproc_t outproc, char *out);
switch (req->rq_proc) {
case CALCULATOR_PROC:
handle_calculator(req, xprt);
return;
case NULLPROC:
svc_sendreply(xprt, (xdrproc_t)xdr_void, NULL);
return;
default:
svcerr_noproc(xprt);
return;