Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2034349
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类:

2006-10-21 20:29:11

RPC是Remote Procedure Call的缩写,翻译成中文就是远程过程调用,是一种在本地的机器上调用远端机器上的一个过程(方法)的技术,这个过程也被大家称为“分布式计算”,是为了提高各个分立机器的“互操作性”而发明出来的技术。
按照“数据即程序”的观点来看,RPC无非是借助一些通信手段来互相传递数据(信息),所也她也是“高”层次的通信手段,无非是这种通信手段看起来更像是“过程的调用”,因为她往往以一个“函数”的面目示人,从而掩盖了她交换信息的实质。
在各种RPC技术中,我想应该以Sun的RPC最为著名,比较流行的网络文件系统NFS就是建立在SUN RPC技术基础之上的。
XMLRPC,顾名思义(我总是喜欢这样把问题简单化,因为一个比较好的名字往往能概括出一个东西的本质,如果某个名字让你摸不着头脑,我推荐你放弃它,因为那个发明这个东西的人都不知道它的实质,所以你也就没有必要在其上浪费无谓的时间和精力。)就是应用了XML技术的RPC。那么什么是XML了?
XML和RPC一样也是一个东西的缩写,这个东西就是eXtensible Markup Language,中文意思就是可扩展标记语言,标记语言就是那种用尖括号(<>)括来括去的那种语言,比如说HTML。XML的可扩展性也体现在它只定义了语言的格式,而并没有定义过多的关键字,也就是通常所说的标记(Tag),所以用户可以自由地选择定义标记。它的这种自由和简单的语法规则也使得它广为流传,被用来表示各种数据。熟悉Lisp语言(一种被称为“一大堆”括号的语言)的同学可能觉得XML和Lisp语言有些类似,不同的是XML用尖括号替代了Lisp语言中的圆括号(())。事实就是他们都是那么相似,那么多语言似乎都是等价的,不同的只是那些应用语言的人。
XML在XMLRPC充当什么角色呢?
答案就是“交换的数据格式”。在Sun RPC中,调用双方传递的数据是二进制的,而在XMLRPC中数据将是XML格式的。那么为什么用XML而不用二进制呢?我想一方面应该是为了兼容更多的语言,因为这个世界上除了C/C++等编译语言,还有很多类似python,perl,javascript等的脚本语言(最近有些文章也称其为“动态语言”,因为他们通常不需要自己管理内存),另一方面是为了隔离操作系统的差异,比如说Little Endian和Big Endian的差异等。基于种种原因,XMLRPC选择了XML这种中间语言作为其信息的格式,然后由各个语言负责将其转变成各自native(本土)的数据类型。关于为了兼容各个语言所发明的中间语言还有IDL(Interface Definition Language:接口定义语言),它被用于CORBA接口的定义。
关于XMLRPC的更多信息请到它的去学习,其中有XMLRPC的(Specification),不过是相当得简单的,因为XMLRPC本身就特别的简单,不相信?好,那下面我就请大家和我一起来学习如何写一个加法的XMLRPC。
服务器端:
因为XMLRPC的消息是用标准的HTTP协议进行传递的,所以我们的服务端也采用运行在apache上的php来开发,作为必要条件,我们需要在我们的系统上安装上php语言的xmlrpc开发库。我选用,因为php在很多情况下并不启用对XMLRPC的支持。下载之后,将其的lib目录拷贝出来并命名为libphpxmlrpc,下面书写我们的第一个XMLRPC实现:
file: xmlrpc_server.php

include ("libphpxmlrpc/xmlrpc.inc");
include ("libphpxmlrpc/xmlrpcs.inc");

if ($_SERVER['REQUEST_METHOD'] != 'POST')
        exit(0);

$add_sig = array(array($xmlrpcString, $xmlrpcInt, $xmlrpcInt));
$add_doc = "Add the two integer together";

function add($params)
{
        global $xmlrpcerruser;

        $val = php_xmlrpc_decode($params);

        $ret = $val[0] + $val[1];

        return new xmlrpcresp(new xmlrpcval($ret, "int"));
}

$server = new xmlrpc_server(array(
        "add" => array(
                "function" => "add",
                "signature" => $add_sig,
                "docstring" => $add_doc
        )));

?>
是不是很简单明了啊?通过上面的代码我想您肯定可以通过CPCS(Copy, Paste, Change, Save)的方法举一反三出更多的XMLRPC来。
客户端:
为了测试我们的程序是否正确,需要写一个客户端来,用什么来写呢?或者是用什么写更方便呢?简单思考之后,python应该比较简单,简单的google了一下,得知xmlrpc的实现已经被纳入官方python的支持之中,窃喜,通过CPCS方法很快就写出了客户端实现,如下:
File: xmlrpc_client.py
#!/bin/env python

from xmlrpclib import *
import sys

# xmlrpc add sample in python
server = Server("~xiaosuo/xmlrpc/xmlrpc_server.php");

try:
        retval = server.add(12, 13)
        print retval

except Error, v:
        print "Error", v
注:我开发的根目录为/home/xiaosuo/xmlrpc/所以网页的目录也就自然为~xiaosuo/xmlrpc/,以下相同。
测试:
xiaosuo@gentux xmlrpc $ ./xmlrpc_client.py
25
Ok!一切顺利。
以下还有几个语言的实现版本请看客们自行分析,并通过CPCS方法学习使用:
使用phpxmlrpc的php版:

include ("libphpxmlrpc/xmlrpc.inc");
include ("libphpxmlrpc/xmlrpcs.inc");

if (isset($_POST['var1']) && isset($_POST['var2'])) {
        $client = new xmlrpc_client("~xiaosuo/xmlrpc/xmlrpc_server.php");
        $msg = new xmlrpcmsg("add", array(
                new xmlrpcval($_POST['var1'], "int"),
                new xmlrpcval($_POST['var2'], "int")));
        $retval = &$client->send($msg);
        if ($retval->faultCode()) {
                print_r("An error occurred: ");
                print_r("Code: " . htmlspecialchars($retval->faultCode())
                        . " Reason: " . htmlspecialchars($retval->faultString()));
        } else {
                $sum = $retval->value()->scalarval();
        }
}

?>

                   "">


xmlrpc add sample in php


>
/>
+
/>

/>



使用来自的xmlrpc命令的shell版:
#!/bin/bash

xmlrpc ~xiaosuo/xmlrpc/xmlrpc_server.php add i/12 i/13
使用xmlrpc-c的C语言版:

/*
 * Compile method:
 * gcc -o xmlrpc_client.out `xmlrpc-c-config --libs --cflags` xmlrpc_client.c -lxmlrpc_client
 */
#include
#include
#include
#include

#define NAME "XML-RPC C Test Client"
#define VERSION "1.0"

#define die_if_fault_occurred(x) \
        do { \
                if ((x)->fault_occurred) \
                abort(); \
        } while(0)

int main(int const argc, const char ** const argv)
{
        xmlrpc_env env;
        xmlrpc_value * resultP;
        int sum;
        char *const url = "~xiaosuo/xmlrpc/xmlrpc_server.php";
        char *const methodName = "add";

        /* Initialize our error-handling environment. */
        xmlrpc_env_init(&env);

        /* Start up our XML-RPC client library. */
        xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
        die_if_fault_occurred(&env);

        /* Make the remote procedure call */
        resultP = xmlrpc_client_call(&env, url, methodName,
                        "(ii)", (xmlrpc_int32) 12, (xmlrpc_int32) 13);
        die_if_fault_occurred(&env);

        /* Get our state name and print it out. */
        xmlrpc_parse_value(&env, resultP, "i", &sum);
        die_if_fault_occurred(&env);
        printf("The sum  is %d\n", sum);

        /* Dispose of our result value. */
        xmlrpc_DECREF(resultP);

        /* Clean up our error-handling environment. */
        xmlrpc_env_clean(&env);

        /* Shutdown our XML-RPC client library. */
        xmlrpc_client_cleanup();

        return 0;
}
使用Frontier库的Perl版本:
#!/bin/env perl
#

use strict;
use warnings;
use Frontier::Client;

my $server = Frontier::Client->new(
        url => "~xiaosuo/xmlrpc/xmlrpc_server.php");

my $sum = $server->call("add", (12, 13));

print $sum . "\n";

是不是开始感叹XMLRPC被支持的程度了,事实上远不止这些,更多的语言支持请到XMLRPC的官方网站的里面去查看。
下篇文章我将介绍我所实现的一个Javascript版本的XMLRPC客户端库。
阅读(5101) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~