使用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)
是线程在完成服务端用户函数调用准备给启用返回结果时出现的。按理应该不是出现段错误的。
如果需要服务器工作稳定的话,需要增加去这个错误的处理。希望能解决的朋友帮忙解决一下。