rpcgen生成的C语言RPC程序报错:RPC: Procedure unavailable
我在完成作业时遇到问题:需使用RPC协议,通过rpcgen生成程序从远程主机获取时间和日期。编写rpctime.x文件后,执行rpcgen -a rpctime.x生成相关文件,并添加标记为//+的代码行。修改Makefile.rpctime将链接库从-lnsl改为-ltirpc后,执行make -f Makefile.rpctime完成编译。运行./rpctime_server和./rpctime_client 127.0.0.1时,客户端始终报错:
call failed: RPC: Procedure unavailable
但服务端仍在正常运行,请求解决该问题。相关代码如下:
rpctime.x
program RPCTIME { version RPCTIMEVERSION { long GETTIME() = 1; } = 1; } = 2000001;
rpctime_server.c
#include "rpctime.h" #include <time.h> //+ long * gettime_1_svc(void *argp, struct svc_req *rqstp) { static long result; time(&result); //+` return &result; }
rpctime_client.c
#include "rpctime.h" #include "time.h" //+` void rpctime_1(char *host) { CLIENT *clnt; long *result_1; char buf[50]; char *gettime_1_arg; #ifndef DEBUG clnt = clnt_create (host, RPCTIME, RPCTIMEVERSION, "udp"); if (clnt == NULL) { clnt_pcreateerror (host); exit (1); } #endif /* DEBUG */ result_1 = gettime_1((void*)&gettime_1_arg, clnt); if (result_1 == (long *) NULL) { clnt_perror (clnt, "call failed"); //此处客户端程序终止 } else { printf("%s\n", ctime_r(result_1, buf)); //+` } #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]; rpctime_1 (host); exit (0); }
Makefile.rpctime
# This is a template Makefile generated by rpcgen # Parameters CLIENT = rpctime_client SERVER = rpctime_server SOURCES_CLNT.c = SOURCES_CLNT.h = SOURCES_SVC.c = SOURCES_SVC.h = SOURCES.x = rpctime.x TARGETS_SVC.c = rpctime_svc.c rpctime_server.c TARGETS_CLNT.c = rpctime_clnt.c rpctime_client.c TARGETS = rpctime.h rpctime_clnt.c rpctime_svc.c rpctime_client.c rpctime_server.c OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o) OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o) # Compiler flags CFLAGS += -g LDLIBS += -ltirpc // 此处原生成-lnsl但无效 RPCGENFLAGS = # Targets all : $(CLIENT) $(SERVER) $(TARGETS) : $(SOURCES.x) rpcgen $(RPCGENFLAGS) $(SOURCES.x) $(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) $(TARGETS_CLNT.c) $(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) $(TARGETS_SVC.c) $(CLIENT) : $(OBJECTS_CLNT) $(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) $(SERVER) : $(OBJECTS_SVC) $(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS) clean: $(RM) core $(TARGETS) $(OBJECTS_CLNT) $(OBJECTS_SVC) $(CLIENT) $(SERVER)
问题原因与解决方法
1. 客户端参数传递错误
IDL中定义的GETTIME()是无参数过程,但客户端调用时传递了(void*)&gettime_1_arg——一个指向未初始化指针的地址,不符合RPC过程的参数定义。
解决:将客户端调用改为result_1 = gettime_1(NULL, clnt);,传递NULL匹配无参数的过程定义。
2. 服务端函数注册不匹配
rpcgen会根据IDL中的过程名生成调度表,需要确保rpctime_svc.c中的rpctime_1_svc_table调度表正确关联gettime_1_svc函数。如果生成的调度表中没有绑定该函数,服务端无法识别客户端的调用请求。
解决:打开rpctime_svc.c,找到struct svcdisp rpctime_1_svc_table[],确保过程ID为1的条目svc_func指向gettime_1_svc。例如:
struct svcdisp rpctime_1_svc_table[] = { { (u_long)1, gettime_1_svc, xdr_void, xdr_long }, { (u_long)0, NULL, NULL, NULL } };
3. 代码语法错误
代码中存在几处语法问题,可能导致程序行为异常:
rpctime_server.c中time(&result); //+后面的多余反引号需要删除rpctime_client.c中#include "time.h"应改为#include <time.h>(系统头文件用尖括号),同时删除后面的多余反引号
4. RPC服务未正确注册
使用tirpc库时,需确保rpcbind服务正常运行,服务端才能注册RPC服务:
- 启动rpcbind:
sudo systemctl start rpcbind - 用
rpcinfo -p命令检查是否有程序号2000001的服务注册
5. Makefile依赖问题
当前Makefile会将你修改后的rpctime_client.c和rpctime_server.c列为rpcgen的生成目标,修改rpctime.x后重新make会覆盖你的代码。
解决:修改Makefile中的TARGETS,移除客户端和服务端代码文件:
TARGETS = rpctime.h rpctime_clnt.c rpctime_svc.c
内容的提问来源于stack exchange,提问作者AlexVs86

