Linux上的RPC多线程服务器

时间:2018-01-21 14:06:47

标签: c linux multithreading pthreads rpc

我正在为大学开发一个RPC项目。我必须实现RPC多线程服务器。我一直在服务器上工作,只有一个程序可以将两个数字相加。我的代码位于:https://github.com/alvmatias/pdytr

这就是我处理客户请求的方法

  /* Register RPC Service */
  /* serve client's requests asynchronously */
  while(1){
  rfds = svc_fdset;
  /* get max value that newly created file descriptor can have in "nfds" */
    switch (select(nfds, &rfds, NULL,NULL,NULL)){
        case -1:   
        case 0 :
            break;
        default: 
            /* Handle RPC request on each file descriptor */
            svc_getreqset(&rfds);
    }

然后我创建线程:

static void ej_prg_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
    /* 2 threads possible for now */
    pthread_t th[2];
    pthread_attr_t attr[2];
    static int id=0;
    /* Used to pass arguments to "funcionA" */
    struct data_str{
        struct svc_req *rqstp;
        SVCXPRT *transp;
        int id;
    } *data_ptr=(struct data_str*)malloc(sizeof(struct data_str));
    /* Set parameters */
    data_ptr-> rqstp = rqstp;
    data_ptr-> transp = transp;
    data_ptr-> id = id;
    /* Create thread */
    printf("Crating thread %d\n", id);
    pthread_attr_init(&attr[id]);
    pthread_attr_setdetachstate(&attr[id],PTHREAD_CREATE_DETACHED);
    pthread_create(&th[id],&attr[id],&funcionA,(void *)data_ptr);
    printf("Thread %d created\n", id);
    id=(id+1)%2;
}

这是每个线程执行的函数:

void *funcionA(void *data) {
    /* Structure for parameters */
    struct thr_data{
        struct svc_req *rqstp;
        SVCXPRT *transp;
        int id;
    } *ptr_data; 
    union {
        operands add_1_arg;
    } argument;
    union {
        int add_1_res;
    } result;
    bool_t retval;
    xdrproc_t _xdr_argument, _xdr_result;

    bool_t (*local)(char *, void *, struct svc_req *);

    /* Get the parameters */
    ptr_data = (struct thr_data  *)data;
    struct svc_req *rqstp = ptr_data-> rqstp;
    register SVCXPRT *transp = ptr_data-> transp;

    printf("Hello thread: %d\n", ptr_data-> id);

    /*Code generated by rpcgen */

    switch (rqstp->rq_proc) {
    case NULLPROC:
        (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
        return;

    case ADD:
        _xdr_argument = (xdrproc_t) xdr_operands;
        _xdr_result = (xdrproc_t) xdr_int;
        local = (bool_t (*) (char *, void *,  struct svc_req *))add_1_svc;
        break;

    default:
        svcerr_noproc (transp);
        return;
    }

    memset ((char *)&argument, 0, sizeof (argument));
    if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
        svcerr_decode (transp);
        return;
    }

    retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
    if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) {
        svcerr_systemerr (transp);
    }
    if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
        fprintf (stderr, "%s", "unable to free arguments");
        exit (1);
    }
    if (!ej_prg_1_freeresult (transp, _xdr_result, (caddr_t) &result)){
        fprintf (stderr, "%s", "unable to free results");
    }
    /* End of rpcgen code */

    /* Exit thread */ /* Remember it's detached */
    printf("Bye thread: %d\n", ptr_data-> id);
    pthread_exit(0);
}

我的问题是我执行了两个客户端,例如:

./ ej_client localhost 20 20 ./ej_client localhost 30 30

两者都得到60作为答案而不是40和60正如预期的那样。我的计划有什么问题?

看了这个问题,答案说--M标志确实生成存根,但svc_calls在linux下不是MT安全的。这是否意味着多线程服务器无法工作? RPC can't decode arguments for TCP transport

编辑:问题似乎在这里

if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) {
        svcerr_systemerr (transp);
    }

我认为" transp"被最新的电话覆盖。因此,发出最新呼叫的客户端会收到前一个呼叫的答案。我该怎么做才能解决这个问题?

EDIT2:我发现了这一点:在当前的实现中,服务传输句柄SVCXPRT包含一个用于解码参数和编码结果的数据区域。因此,在调用执行此操作的函数的线程之间无法自由共享此结构。检查:https://docs.oracle.com/cd/E19683-01/816-0214/6m6nf1p6o/index.html 我该怎么做才能使它安全,所以它可以在多个线程之间自由共享?

谢谢Matias。

0 个答案:

没有答案