【问题标题】:How do I send an array of over the RPC?如何通过 RPC 发送数组?
【发布时间】:2015-02-12 03:45:33
【问题描述】:

使用libtirpc 库通过 RPC 发送数组有点困难。在客户端-服务器会话期间发送原语很简单:

// Client-side boilerplate
struct timeval tout = { 1, 0 };
int in = 42;
clnt_call (cln, 1, (xdrproc_t)xdr_int, (char*)&in,
    (xdrproc_t)xdr_void, NULL, tout);    

// Server-side boilerplate
int in;
svc_getargs (xprt, (xdrproc_t)xdr_int, (char*)&in);
assert (in == 42);

xdrproc_t 函数签名是bool_t (*xdrproc_t) (XDR *, void *, ...);xdr_int(3)xdr_long(3) 和其他原始序列化程序没有可变参数,因此可以直接使用 clnt_call(3)svc_getargs(3) 函数使用它们。然而,用于序列化可变长度数组的 xdr_array(3) 函数需要更多参数:

bool_t xdr_array(XDR *xdrs, char **arrp, unsigned int *sizep,
                 unsigned int maxsize, unsigned int elsize,
                 xdrproc_t elproc);

clnt_call(3)svc_getargs(3) 函数不能真正将这些参数传递给函数,因此创建包装函数似乎是解决问题的最干净的解决方案:

// Client-side boilerplate
long a = 1, b = 2;
long * arr[] = { &a, &b };
unsigned int amount = sizeof(arr) / sizeof(long*);
bool_t xdr_array_wrapper (XDR * xdr, void * ptr) {
    return xdr_array (xdr, ptr, &amount, amount,
        sizeof(long), (xdrproc_t)xdr_long);
}

struct timeval tout = { 1, 0 };
long out;
clnt_call (cln, 1, (xdrproc_t)xdr_array_wrapper,
    (char*)arr, (xdrproc_t)xdr_long, (char*)&out, tout);

// Server-side boilerplate
long * arr[2];
unsigned int amount = sizeof(arr) / sizeof(long*);
bool_t xdr_array_wrapper (XDR * xdr, void * ptr) {
    return xdr_array (xdr, ptr, &amount, amount,
        sizeof(long), (xdrproc_t)xdr_long);
}
svc_getargs (xprt, (xdrproc_t)xdr_array_wrapper, (char*)arr);
long a = *arr[0], b = *arr[1];

但是,由于某些未知原因,只有数组的第一个元素(变量a)被传输,而另一个包含垃圾。我做错了什么?

【问题讨论】:

    标签: c linux unix rpc


    【解决方案1】:

    您错误地使用了xdr_array 有两个原因。

    1. 它只能处理动态分配的数组。
    2. 您正在尝试发送int* 数组,就好像它是int 数组一样。

    正确的使用方法是这样的(盗自IBM并简化,更完整的处理参考链接):

    typedef struct xarray
    {
            int size;
            int *p_array;
    } xarray ;
    
    bool_t xdr_xarray(XDR *xdrs, xarray *p_xarray )
    {
        return xdr_array(
                     xdrs,
                     (char**)(&(p_xarray->p_array)),
                     &(p_xarray->size),
                     MAX_INT,
                     sizeof(int),
                     (xdrproc_t)xdr_int)) 
    }
    

    注意以下几点:

    1. p_array 是一个指向动态分配数组的指针。
    2. 它是int 的数组,而不是指针的数组。
    3. 我们将p_array 的地址传递给xdr_array,以便在解码时分配所需大小的数组并将其分配给p_array

    如果你想要固定大小的数组,你需要使用xdr_vector

    typedef struct xvector
    {
            int vector[42];
    } xarray ;
    
    bool_t xdr_xvector(XDR *xdrs, xarray *p_xvector )
    {
        return xdr_vector(
                     xdrs,
                     (char*)p_xvector->vector,
                     42,
                     sizeof(int),
                     (xdrproc_t)xdr_int)) 
    }
    

    请注意,您仍然不应该在此处使用指针数组。

    RPC 编译器会根据您的数据结构自动生成 XDR 过程,因此请考虑使用一个。

    【讨论】:

    • 谢谢,xdr_vector(3) 正是我所需要的。我最终使用了一个指针数组,因为xdr_array(3) 导致SIGSEGV 信号被发送到进程,否则。现在我看到这是因为该函数需要一个指向数组的双指针,而我没有给它(arr 等于 &arr 带有一个静态分配的数组)。非常感谢该链接,我的代码基于手册页,它比我想要的更简洁。
    猜你喜欢
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2011-08-02
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多