调用RPC函数返回时触发Segmentation Fault问题求助
RPC返回时触发段错误问题
客户端调用RPC函数传入整数参数,服务端将其转换为符号地址,服务端能成功转换并打印结果,但返回时触发Segmentation Fault(段错误)。
服务端代码
#include <iostream> #include <cstring> #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/rpc.h> #include <netdb.h> char *from_number_to_symbolic(int number) { struct sockaddr_in temp = { AF_INET, SOCK_STREAM, { number } }; static char symbolic[100]; getnameinfo((struct sockaddr *) &temp, sizeof(struct sockaddr_in), symbolic, 100, NULL, 0, 0); std::cout << std::endl << symbolic << std::endl; return symbolic; } int main(int argc, char *argv[]) { registerrpc(42700, 1, 1,(char* (*)(char *)) from_number_to_symbolic, (xdrproc_t) xdr_int, (xdrproc_t) xdr_wrapstring); svc_run(); return 0; }
客户端代码
#include <iostream> #include <cstdlib> #include <rpc/rpc.h> #include <arpa/inet.h> #include <netdb.h> int from_numeric_to_int(char *numeric) { struct in_addr number; inet_pton(AF_INET, numeric, &number); return number.s_addr; } int main(int argc, char *argv[]) { if (argc != 2) { exit(1); } char **num_adrress = &argv[1]; int *int_adrress = new int; *int_adrress = from_numeric_to_int(*num_adrress); char **symbolic = new char*; callrpc("127.0.0.1", 42700, 1, 1, (xdrproc_t) xdr_int, (char *)num_adrress, (xdrproc_t) xdr_wrapstring, symbolic); std::cout << *symbolic << std::endl; return 0; }
运行步骤
- 启动服务端:
./server - 执行客户端:
./client 64.233.166.94
现象:服务端打印预期结果208-107-167-85-dynamic.midco.net,但返回时触发段错误。
问题原因与修复
1. 核心问题点
- 服务端函数签名不匹配:
from_number_to_symbolic期望接收int参数,但注册RPC时被强制转换为char* (*)(char*),RPC框架会按错误的签名传递参数,导致内存访问越界。 - 客户端参数传递错误:
callrpc传入的是原始字符串指针,而非转换后的整数指针,导致服务端解析到错误的数据。 - 服务端
sockaddr_in初始化错误:错误将sin_port赋值为SOCK_STREAM,不符合地址结构规范。
修复后的服务端代码
#include <iostream> #include <cstring> #include <rpc/types.h> #include <rpc/xdr.h> #include <rpc/rpc.h> #include <netdb.h> char *from_number_to_symbolic(char *arg) { // 从RPC序列化数据中解析出int参数 int number; XDR xdrs; xdrmem_create(&xdrs, arg, sizeof(int), XDR_DECODE); if (!xdr_int(&xdrs, &number)) { return strdup("Invalid parameter"); } xdr_destroy(&xdrs); // 正确初始化sockaddr_in结构 struct sockaddr_in temp; memset(&temp, 0, sizeof(temp)); temp.sin_family = AF_INET; temp.sin_addr.s_addr = number; static char symbolic[100]; getnameinfo((struct sockaddr *) &temp, sizeof(struct sockaddr_in), symbolic, sizeof(symbolic), NULL, 0, 0); std::cout << std::endl << symbolic << std::endl; return symbolic; } int main(int argc, char *argv[]) { registerrpc(42700, 1, 1, (char* (*)(char*))from_number_to_symbolic, (xdrproc_t)xdr_int, (xdrproc_t)xdr_wrapstring); svc_run(); return 0; }
修复后的客户端代码
#include <iostream> #include <cstdlib> #include <rpc/rpc.h> #include <arpa/inet.h> #include <netdb.h> int from_numeric_to_int(char *numeric) { struct in_addr number; inet_pton(AF_INET, numeric, &number); return number.s_addr; } int main(int argc, char *argv[]) { if (argc != 2) { exit(1); } int *int_address = new int; *int_address = from_numeric_to_int(argv[1]); char **symbolic = new char*; // 传入转换后的整数指针 callrpc("127.0.0.1", 42700, 1, 1, (xdrproc_t)xdr_int, (char *)int_address, (xdrproc_t)xdr_wrapstring, symbolic); std::cout << *symbolic << std::endl; // 释放RPC分配的内存 xdr_free((xdrproc_t)xdr_wrapstring, (char*)*symbolic); delete int_address; delete symbolic; return 0; }
额外说明
- 客户端需调用
xdr_free释放RPC框架分配的字符串内存,避免内存泄漏。 - 服务端使用
static char存储返回值是安全的,因为RPC框架会在返回前完成数据序列化。
内容的提问来源于stack exchange,提问作者Tomislav Farkaš
相关产品推荐
相关产品推荐

