当前位置: 首页 >> 程序设计 >> Linux下RPC调用编程
 

Linux下RPC调用编程

作者:      来源:http://blog.csdn.net/linux_coder     发表时间:2007-05-01     浏览次数:      字号:    

linux rpc在内核中实现,源代码位置是net/sunrpc/
sunrpc不仅实现了rpc的调度,同时将rpc请求构造解析发送接受的通用部分进行了提取。要定义自己的rpc调用仅需要实现那些非通用的部分,下面简要介绍怎么实现一个自己的rpc客户端(2.4内核)


主要数据结构介绍

1。rpc请求


/*
 * This is the RPC buffer
 */
struct rpc_iov {
    struct iovec        io_vec[MAX_IOVEC]; //使用10个 iovec 可以操作分散的buffer
    unsigned int        io_nr;
    unsigned int        io_len;
};

/*
 * This describes a complete RPC request
 */
struct rpc_rqst {
    /*
     * This is the user-visible part
     */
    struct rpc_xprt *    rq_xprt;        /* RPC client */
    struct rpc_timeout    rq_timeout;        /* timeout parms */
    struct rpc_iov        rq_snd_buf;        /* send buffer 发送缓冲区*/
    struct rpc_iov        rq_rcv_buf;        /* recv buffer 接受缓冲区*/

    /*
     * This is the private part
     */
    struct rpc_task *    rq_task;    /* RPC task data */
    __u32            rq_xid;        /* request XID */
    struct rpc_rqst *    rq_next;    /* free list */
    volatile unsigned char    rq_received : 1;/* receive completed */

    /*
     * For authentication (e.g. auth_des)
     */
    u32            rq_creddata[2];
    
    /*
     * Partial send handling
     */
    
    u32            rq_bytes_sent;    /* Bytes we have sent */

#ifdef RPC_PROFILE
    unsigned long        rq_xtime;    /* when transmitted */
#endif
};
#define rq_svec            rq_snd_buf.io_vec
#define rq_snr            rq_snd_buf.io_nr
#define rq_slen            rq_snd_buf.io_len
#define rq_rvec            rq_rcv_buf.io_vec
#define rq_rnr            rq_rcv_buf.io_nr
#define rq_rlen            rq_rcv_buf.io_len




流程介绍

1。注册自己的rpc调用


#ifndef MAX
#define MAX(a, b)      (((a) > (b))? (a) : (b))
#endif


#define PROC(proc, argtype, restype, timer)                             \
    {    "xxx_clnt" #proc,                                      \
    (kxdrproc_t) xxx_clnt_encode_##argtype,                    \
    (kxdrproc_t) xxx_clnt_decode_##restype,                    \
    MAX(XXX_##argtype##_sz,XXX_##restype##_sz) ,   \
    timer                                              \
    }

// 这里注册了3个rpc调用,分别是:read、write、getsize
static struct rpc_procinfo      xxx_clnt_procedures[4] = {
    PROC(null, void, void, 0),
    PROC(read, readargs, readres, 0),
    PROC(write, writeargs, writeres, 0),
    PROC(getsize, getsizeargs, getsizeres, 0),
}

/*上面结构实际效果是下面这样
其中注册了每个rpc请求和返回的编码解码函数,在步骤4中描述
static struct rpc_procinfo      xxx_clnt_procedures[4] = {
    {"xxx_clnt_null", (kxdrproc_t)xxx_clnt_encode_void, (kxdrproc_t)xxx_clnt_decode_void, MAX(XXX_void_sz, XXX_void_sz), 0},
    {"xxx_clnt_read", (kxdrproc_t)xxx_clnt_encode_readargs, (kxdrproc_t)xxx_clnt_decode_readres, MAX(XXX_readargs_sz, XXX_readres_sz), 0},
    {"xxx_clnt_write", (kxdrproc_t)xxx_clnt_encode_writeargs, (kxdrproc_t)xxx_clnt_decode_writeres, MAX(XXX_writeargs_sz, XXX_writeres_sz), 0},
    {"xxx_clnt_getsize", (kxdrproc_t)xxx_clnt_encode_getsizeargs, (kxdrproc_t)xxx_clnt_decode_getsizeres, MAX(XXX_getsizeargs_sz, XXX_getsizeres_sz), 0},
};
*/

static struct rpc_version xxx_clnt_version1 = {
    1,
    sizeof(xxx_clnt_procedures)/sizeof(xxx_clnt_procedures[0]),
    xxx_clnt_procedures
};

static struct rpc_stat xxx_clnt_rpcstat;

static struct rpc_version* xxx_clnt_version[] = {
    NULL,
    &xxx_clnt_version1,
};

struct rpc_program xxx_clnt_program = {
    "xxx",
    XXX_PROGRAM,
    sizeof(xxx_clnt_version)/sizeof(xxx_clnt_version[0]),
    xxx_clnt_version,
    &xxx_clnt_rpcstat,
};


2。在运行前先创建rpc调度线程


if (rpciod_up() != 0) {
        printk("xxx:unable to run async scheduler!\n");
        return -1;
}


3。实现rpc调用函数

以read为例

struct xxx_readargs readargs;    //用户自定义请求参数结构
struct xxx_readres readres;        //用户自定义请求返回结构
struct rpc_message read_msg = {
    1,
    &readargs,                                    //以指针形式注册到rpc消息结构中
    &readres,
    NULL,
};

// 同步的情况
int xxx_read(???)
{
    int retval = 0;

    // 设置发送的属性
    readargs.??? = ??;
    readargs.??? = ??;

    // 设置返回参数的属性
    readres.??? = ??;

    retval = rpc_call_sync(xxx_clnt, &read_msg, 0);
    if (retval < 0){
        // 出错情况
    } else {
        // 获取返回值
    }

    return retval;
}


4。rpc调用参数和返回值的解析函数


步骤3中有用户自定义的参数返回值
struct xxx_readargs readargs;    //用户自定义请求参数结构
struct xxx_readres readres;        //用户自定义请求返回结构

在进行socket包发送接受时需要进行它们的编码和解析
主要是为了便利用户定义参数的灵活性,比如数据可以通过iovec分散的保存

下面是nfs的编码函数

// 用户自定义的请求结构指针args被传入函数
static int
nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
    unsigned int    nr;
    u32 count = args->count;

    // 部分属性参数的打包
    p = xdr_encode_fhandle(p, args->fh);
    p = xdr_encode_hyper(p, args->offset);
    *p++ = htonl(count);
    *p++ = htonl(args->stable);
    *p++ = htonl(count);
    req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);

    /* Get the number of buffers in the send iovec */
    nr = args->nriov;

    if (nr+2 > MAX_IOVEC) {
        // rpc请求只能最大支持10个iovec
        printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
        return -EINVAL;
    }

    /* Copy the iovec 通过拷贝iovec到将要发送的数据导入到了rpc里面*/
    memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));

    req->rq_slen += count;
    req->rq_snr  += nr;

    return 0;
}

责任编辑 webmaster

 
 
 
 
 
评论更多>>
 
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •