gpt4 book ai didi

c - RPC无法解码TCP传输的参数

转载 作者:太空狗 更新时间:2023-10-29 15:32:11 26 4
gpt4 key购买 nike

我正在根据此页面上的示例在多线程RPC服务器上工作:
http://bderzhavets.blogspot.ca/2005/11/multithreaded-rpc-server-in-white-box.html

不幸的是,它并没有开箱即用,在追寻了一段时间的错误之后,我发现服务器无法解码参数(基于squareproc_2的返回码)。在调用squareproc_2_svc函数中的serv_request之后,服务器端的执行似乎停止了。请参阅来自square_svc.c的以下代码中的case: SQUAREPROC

void *serv_request(void *data)
{
struct thr_data *ptr_data = (struct thr_data *)data;
{
square_in argument;
square_out result;
bool_t retval;
xdrproc_t _xdr_argument, _xdr_result;
bool_t (*local)(char *, void *, struct svc_req *);
struct svc_req *rqstp = ptr_data->rqstp;
register SVCXPRT *transp = ptr_data->transp;
switch (rqstp->rq_proc) {
case NULLPROC:
printf("NULLPROC called\n");
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case SQUAREPROC:
_xdr_argument = (xdrproc_t) xdr_square_in;
_xdr_result = (xdrproc_t) xdr_square_out;
printf("_xdr_result = %ld\n",_xdr_result);
local = (bool_t (*) (char *, void *, struct svc_req *))squareproc_2_svc;
break;
default:
printf("default case executed");
svcerr_noproc (transp);
return;
}
memset ((void *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
printf("svc_getargs failed");
svcerr_decode (transp);
return;
}
retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
printf("serv_request result: %d\n",retval);
if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result))
{
printf("something happened...\n");
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
if (!square_prog_2_freeresult (transp, _xdr_result, (caddr_t) &result))
fprintf (stderr, "%s", "unable to free results");
return;
}
}

这是来自文件square_server.c的 squareproc_2_svc的实现:
bool_t squareproc_2_svc(square_in *inp,square_out *outp,struct svc_req *rqstp)
{
printf("Thread id = '%ld' started, arg = %ld\n",pthread_self(),inp->arg1);
sleep(5);
outp->res1=inp->arg1*inp->arg1;
printf("Thread id = '%ld' is done %ld \n",pthread_self(),outp->res1);
return(TRUE);
}

客户端输出:
yak@AcerPC:~/RPC/multithread_example$ ./ClientSQUARE localhost 2
squareproc_2 called
xdr_square_in result: 1
function call failed; code: 11

服务器端输出:
yak@AcerPC:~/RPC/multithread_example$ sudo ./ServerSQUARE 
creating threads
SQUAREPROC called
xdr_square_in result: 0

如您所见,xdr_square_in在服务器端返回FALSE结果。
这是square.x
struct square_in {
long arg1;
};

struct square_out {
long res1;
};

program SQUARE_PROG {
version SQUARE_VERS {
square_out SQUAREPROC(square_in) = 1;
} = 2 ;
} = 0x31230000;

和square_xdr.c
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/

#include "square.h"

bool_t
xdr_square_in (XDR *xdrs, square_in *objp)
{
register int32_t *buf;
int retval;
if (!xdr_long (xdrs, &objp->arg1)) retval = FALSE;
else retval = TRUE;
printf("xdr_square_in result: %d\n",retval);
return retval;
}

bool_t
xdr_square_out (XDR *xdrs, square_out *objp)
{
register int32_t *buf;
int retval;
if (!xdr_long (xdrs, &objp->res1)) retval = FALSE;
else retval = TRUE;
printf("xdr_square_out result: %d\n",retval);
return retval;
}

我正在Ubuntu 14.04 LTS中工作,使用 rpcgen -a -M生成 stub 和xdr代码,并使用 gcc进行编译。

仅在将TCP用作传输方法时才会出现该错误。我可以使用UDP作为传输来获得结果,但是当多个客户端的请求同时到达时,某些调用将失败。我希望能够支持多达15个客户。当我尝试使用UDP和10个客户端时,10个调用中有2个失败,返回码与 squareproc_2不同。

最佳答案

您遇到了一些问题。

在xen页面上,当它在square_prog_2中执行pthread_create时,首先会调用pthread_attr_setdetachstate,但在此之前需要执行pthread_attr_init。同样,attr似乎是静态的/全局的-将其放入函数的堆栈框架中。

square_prog_2获得两个参数:rqstp和transp。这些被保存到malloc的struct data_str中[因此每个线程都有自己的副本]。但是,我想知道rqstp和transp的值是什么(例如printf(“%p”))。它们需要不同,否则每个线程在尝试使用它们时将相互冲突(因此需要pthread_mutex_lock)。 malloc不会克隆rqstp/transp,所以如果它们相同,那就是问题所在,因为您可能有两个线程试图同时对相同的缓冲区进行riff。

返回码为11。除非有一些特殊的代码,否则看起来像线程上的SIGSEGV。 rqstp/transp重叠将完全解决此问题。

您可能需要重新设计,因为我怀疑XDR不是线程安全的-也不必这样做。另外,我不认为svc_ *是线程安全/可识别的。

启动单线程。作为测试,请square_prog_2直接调用serv_request(例如,不要执行pthread_ *)。我敢打赌,这在所有模式下都有效。

如果是这样,请戴上帽子-使用线程的示例代码已损坏-充满了竞争条件,并且会出现段错误等。如果您不习惯使用线程(无需执行x *这样的轻量级任务, x),您可以按原样享受。

否则,解决方案会更加复杂。主线程必须完成对套接字的所有访问以及所有XDR解析/编码。它不能使用svc_run-您必须自己滚动。 child 只能做实际的工作(例如x * x),而不能触摸 socket /要求/传送等。

主线程:

while (1) {
if (svc_getreq_poll()) {
// parse XDR
// create data/return struct for child thread
// create thread
// add struct to list of "in-flight" requests
}

forall struct in inflight {
if (reqdone) {
// take result from struct
// encode into XDR
// do send_reply
// remove struct from list
}
}
}

对于子结构,它看起来像:
struct child_struct {
int num;
int num_squared;
};

并且 child 的线程函数变成了一个衬里: ptr->num_squared = ptr->num * ptr->num
更新:Linux或FreeBSD上不支持多线程RPC服务器 而不是

这是一个文档: https://www.redhat.com/archives/redhat-list/2004-June/msg00439.html这是一个更干净的示例。

由此可见:请记住-Linux不支持rpcgen的选项。图书馆电话
在Linux下,SunOS RPC提供的用于构建多线程RPC服务器的功能也不可用

这是Linux rpcgen的手册页: http://linux.die.net/man/1/rpcgen没有提及-M。 IMO,这意味着rpcgen程序具有该选项并确实生成 stub ,但是底层支持不存在,因此他们将其排除在文档之外。

这是FreeBSD的手册页[以及不支持的原因]: http://www.freebsd.org/cgi/man.cgi?query=rpcgen&sektion=1&manpath=FreeBSD+5.0-RELEASE请参阅-M的文档:

M-生成用于传递参数和结果的多线程安全 stub
在rpcgen生成的代码和用户编写的代码之间。这个选项
对于想要在代码中使用线程的用户很有用。但是,rpc_svc_calls(3)函数还不是MT安全的,因此
表示rpcgen生成的服务器端代码将不是MT安全的。

另一种方法:

为什么还要打扰RPC/XDR?对于要使用的大型阵列,开销非常大。大多数标准用途是用于黄页之类的东西,它们没有太多的数据。

如今,大多数系统都是低位优先的。只需将 native 缓冲区加载到您直接打开的套接字即可。在服务器上,让守护程序进行监听,然后派生一个 child ,让该 child 进行接受,读入数据,进行计算并发回答复。在最坏的情况下, child 将需要进行字节序交换,但是使用bswap_32可以在紧密循环中轻松完成。

在每个消息的开始处,在任一方向上都添加了一个简单的小控制结构,该结构以数据有效载荷为前缀:
struct msgcontrol {
int what_i_am;
int operation_to_perform;
int payload_length;
int payload[0];
};

特别说明:我之前已经在商业上进行过此操作(例如,MPI并自行运行),您可能必须发出setsockopt调用,以将内核套接字缓冲区的大小增加到足以维持大量数据的能力

实际上,现在考虑到这一点,如果您不想自己动手,那么MPI可能会引起您的兴趣。但是,使用它后,我不是真正的粉丝。它有意想不到的问题,我们不得不删除它,以便直接控制我们的套接字。

关于c - RPC无法解码TCP传输的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33202866/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com