我正在为大学开发一个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);
}
这是远程程序:
bool_t add_1_svc(operands *argp, int *p, struct svc_req *rqstp)
{
bool_t result;
printf("Got request: adding %d, %d\n", argp->x, argp->y);
/* Add two numbers */
*p=argp->x + argp->y;
/* Execute a 4 seconds sleep to check multithreading */
sleep(4);
/* Return ok */
result = 1;
return (result);
}
我的问题是我执行了两个客户端,例如:
./ 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 :(得分:0)
svc_getargs()不是线程安全的。此函数从主rpc线程复制数据。当你调用这个函数时,它会复制当前的请求数据,你想从回调函数中调用它,将数据复制到结构中,然后使用线程中的数据。否则你可能会看到一些不可预测的结果。
我会使用rpcgen -MNC< .x文件名>然后创建一个包装函数,调用svc_getargs()来复制当前请求数据,然后通过struct变量将数据传递给线程进行处理