LINUX系统上使用多线程化的RPC

来源:互联网 发布:京东卖家软件 编辑:程序博客网 时间:2024/06/06 20:48

使用RPC时,在LINUX系统上使用rpcgen -M并不能生成具有多线程的RPC代理存根,只是生成的代码具有线程安全特性。在网络有一些网友讨论了一种实现方式,就是在接收到客户端的请求时,建立一个线程来处理客户端代码,这方

式一个外国的朋友给出了实现代码(http://www.redhat.com/archives/open-source-now-list/2004-June/msg00000.html ),但在复制到我的LINUX(LINUX RHL5)时,并不能成功运行。在国内有一作者也写一个示例,是针对

UNIX网络编程第一卷求平方根的示例写的网址如下:http://blog.chinaunix.net/u1/37472/showart_726114.html
我使用该示例仍然没能得到运行(RPC: Procedure unavailable),通过增加主线程的延时,得到了正确运行。
但是通过增加延时只会加慢RPC服务器处理数据的时间,如果时间过长,会引起RCP调用超时,如果过短,而且RCP调用(新开的线程)还没有处理完成,也是会存在着问题的。我在本地通过延时一秒,并间隔一定时隙调用100次,发

现服务器出现段错误。
我做过将使用指针修改为变量,出现错误:RPC: Server can't decode arguments,后来我发现RPC调用参数的结构体并不是一级指针,而是多级指针。也就是说该结构中还是指针变量成员。

经过试验我总结出RPC调用的时间顺序时:
svc_run()
|->   获得客户请求
|       为客户数据建立参数
|       调用服务器存根(非多线程)
|       创建一个新线程代替服务器存根执行体  |    新线程开始
|       完成线程创建                                   |    访问参数
|<----清除参数                                         |    访问错误 (数据已经清除)
 
在插入时间等待之后的时间顺序为:
svc_run()
|->   获得客户请求
|       为客户数据建立参数
|       调用服务器存根(非多线程)
|       创建一个新线程代替服务器存根执行体   |    新线程开始
|       完成线程创建                                    |    访问参数
|       等待...                                             |    访问用户服务端执行体
|<-----清除参数                                        |    执行体处理
                                                              |     .........
                                                              |    返回客户端
上图展示了取得等待时间之后的调用顺序,这样就可以成功。如果客户连续请求,而客户端访问参数还没有完成时,将会导致问题,而且这个时间的设定与服务器的处理能力相关,运行负载相关。

为些我想到了使用一个线程锁来解决等待的问题,并且在产生100次连续调用之后,也没有发现问题,但并不代表没有问题,因为对于RPC的运行流程我只是在猜测,而且在返回给客户时,没有一些原始状态信息是否可以正常返回呢

?如果返回数据不是一个简单的数值,而是一个结构体数据,那会怎么样呢?所以希望能看到这时原朋友,如果使用时出现了问题,请告知我。我也会在有时间的时候来测试一下。

如下是服务端代码,是通过rpcgen生成之后再修改的.

在代码的#70行处,可以看到在准备为客户求建立一个线程,在创建完线程之后,在#73行开始等待锁,也就是在这个时候等待参数被RPC解析并到调用服务端处理代码期间。在#152行,我释放了锁,这样在主线程就可以返回了,而辅助线程将进入自定义的服务器处理函数。这样就实现了一个比较合理的等待。

下面将程序代码以及MAKEFILE文件发到此处,希望需要这个方面信息的朋友可以测试一下,并提出更多的想法。

square.x

server.c 服务务用户处理函数所在地

client.c 客户调用,在这里希望注意的就是clnt_destroy函数的调用,尤其是在错误的时候没有调用时,将导致客户与服务器之间保持了一个连接(在LINUX上表示找开了一个文件),如果出现多次,将在服务器上相当于打开了许多的TCP连接(文件),将导致服务器程序因为受操作系统的进程打开文件数限制而出错(打开文件时)。所以请一定要注意!

Makefile 编译文件

 

编译方法,先使用make命令编译程序,然后再将square_svc.c文件覆盖,再编译,方能实现多线程。

最后,我发现,如果客户端过早终止,服务器将出错。问题出在square_svc.c文件#156行,在给TCP回复的时候出的问题:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208173680 (LWP 28672)]
0x00ac7ef5 in writetcp () from /lib/libc.so.6
(gdb) where
#0  0x00ac7ef5 in writetcp () from /lib/libc.so.6
#1  0x00aca570 in xdrrec_endofrecord_internal () from /lib/libc.so.6
#2  0x00ac7e00 in svctcp_reply () from /lib/libc.so.6
#3  0x00ac682c in svc_sendreply_internal () from /lib/libc.so.6
#4  0x08048b39 in square_prog_2_thread_func (rqstp=0xbfe9af18, transp=0x8f36708, pmutex=0x80491a4)
    at square_svc.c:156
#5  0x08048a3a in square_prog_thread_func (param=0x8f33008) at square_svc.c:99
#6  0x00b462db in start_thread () from /lib/libpthread.so.0
#7  0x00aa014e in clone () from /lib/libc.so.6
(gdb)
是线程在完成服务端用户函数调用准备给启用返回结果时出现的。按理应该不是出现段错误的。

如果需要服务器工作稳定的话,需要增加去这个错误的处理。希望能解决的朋友帮忙解决一下。

 

原创粉丝点击