首页 > 代码库 > [UNIX网络编程] sun rpc实现的简单echo服务器

[UNIX网络编程] sun rpc实现的简单echo服务器

RPC的全称是Remote Procedure Call,它能够在本地以函数调用的形式来实现网络操作,让程序员集中关注于业务逻辑,不用关心底层的数据通信。

这里不会详细讲解RPC的原理,而是用一个简单的echo服务器的例子来说明如何使用RPC。

最早实现的RPC是sun rpc,现在它已经移植到了大多数操作系统。

使用RPC,程序员只需要关注客户与服务器之间数据传送的格式以及如何远程过程的定位,客户端如何调用本地函数以调用远程函数,服务器远程过程的实现。


1 客户端与服务器之间数据的交互

客户与服务器之间的数据传送是通过定义一个.x文件来实现的。在这个文件中,程序员可以定义客户端与服务器交互的数据格式,例如,我们的echo.x内容如下:

struct hello {
	char text[256];
};

struct hello_echo {
	char text_echo[256];
};

program ECHO_PROG {
	version ECHO_VERS {
		hello_echo ECHOPROC(hello) = 1;
	} = 1;
} = 0x31230000;

echo.x中定义了两个结构体,一个是struct hello,它是客户端向服务器发送的数据,一个是struct hello_echo,它服务器向客户端发送的内容。下面定义了一个program ECHO_PROG,这个结构体用于远程过程的定位,当客户端发送数据过来时,服务器需要确定调用哪个过程。


2 客户端调用远程过程

客户端通过一个CLIENT的句柄来调用远程过程:

        CLIENT *cl;
	hello in;
	hello_echo *outp;

	if(argc != 3) {
		fprintf(stderr, "usage: client <hostname> <integer_value>\n");
		exit(0);
	}

	cl = clnt_create(argv[1], ECHO_PROG, ECHO_VERS, "tcp");
	strncpy(in.text, argv[2], strlen(argv[2]));
	in.text[strlen(argv[2])] = 0;
	if((outp = echoproc_1(&in, cl)) == NULL) {
		fprintf(stderr, "%s\n", clnt_sperror(cl, argv[1]));
		exit(0);
	}
	printf("result: %s\n", outp->text_echo);

首先定义一个CLIENT的指针和两个用于发送数据和接收数据的参数,然后通过服务器的IP地址和远程过程的程序名以及版本号创建CLIENT,然后将命令行中的文本拷贝到发送参数hello in中,最后调用远程过程echoproc_1(),其中echoproc是在program ECHO_PROG中定义的函数名,但是所有字母都小写,1是该函数的版本号ECHO_VERS。


3 服务器远程过程的定义

服务器的主程序通过rpcgen自动生成,程序员只需要定义远程过程即可。

#include "echo.h"

hello_echo *echoproc_1_svc(hello *inp, struct svc_req *rqstp)
{
	static hello_echo out;
	strncpy(out.text_echo, inp->text, strlen(inp->text));
	out.text_echo[strlen(inp->text)] = 0;

	return (&out);
}

客户端调用的远程过程名是echoproc_1,而服务器真正执行的远程过程名则是echoproc_1_svc。

echoproc_1_svc()的参数和返回值已经确定了只要编写函数体即可。

这里的功能就是简单的回射,因此,执行一个strncpy就行,最后返回一个hello_echo的地址,由于是局部变量的地址,因此,要用静态局部变量。


4 程序的运行

首先对echo.x执行rpcgen得到头文件和服务器的主程序:

rpcgen -C echo.x

然后分别对客户端和服务器端进行编译:

gcc -o client client.c echo_clnt.c echo_xdr.c
gcc -o server echo_svc.c server_func.c echo_xdr.c

执行服务器:

./server

出现以下错误:

Cannot register service: RPC:  Authentication error; why = Client credential too weak

意思是认证错误,以root权限执行即可:

sudo ./server

然后执行客户端:

./client 127.0.0.1 abc

第三个参数发送什么,服务器就回送什么。


5 小结

RPC简化了开发网络应用的步骤,只要定义通信的数据和服务器的远程过程,就能够在客户端调用本地过程,RPC运行时库就能够自动调用远程过程。这对于开发大型的网络应用是十分方便的。