一.简介
XML-RPC的全称是XML Remote Procedure Call,即XML远程方法调用。
它是一套允许运行在不同操作系统、不同环境的程序实现基于Internet过程调用的规范和一系列的实现。 这种远程过程调用使用http作为传输协议,XML作为传送信息的编码格式。 XML-RPC的定义尽可能的保持了简单,但同时能够传送、处理、返回复杂的数据结构。
XML-RPC是使用HTTP协议做为传输协议的RPC(远程方法调用)机制,使用XML文本的方式传输命令和数据。
一个RPC系统,必然包括2个部分:
1.RPC Client,用来向RPC Server调用方法,并接收方法的返回数据;
2.RPC Server,用于响应RPC Client的请求,执行方法,并回送方法执行结果。
RPC是Remote Procedure Call的缩写,翻译成中文就是远程方法调用,是一种在本地的机器上调用远端机器上的一个过程(方法)的技术,这个过程也被大家称为“分布式计算”,是为了提高各个分立机器的“互操作性”而发明出来的技术。
XML-RPC的可用版本
XML-RPC client和XML-RPC server都有很多版本的实现。一般而言,一个实现版本都会同时实现client/server。但由于都满足xml rpc规范,从理论上讲,任何一个版本的XML-RPC client实现与任何一个版本的XML-RPC server都能配套使用。
更进一步,由于XML-RPC以XML文本的方式,使用http协议传输,所以与编程语言无关。例如:XML-RPC client的已实现版本包括了:perl,php,python,c/c++,java,等等;XML-RPC server的实现语言包括perl,java,等。
同一种编程语言所实现的版本也不止一个。例如java版的实现有:
Marque的XML-RPC现在已经和Redstone XML-RPC Library合并(http://xmlrpc.sourceforge.net/)
Apache的XML-RPC实现,这个项目隶属于apache web service项目,故URL地址开头为ws.apache(http://ws.apache.org/)下载链接http://archive.apache.org/dist/ws/有些时候直接点进项目去,无法通过镜像下载,这时候就可以访问http://archive.apache.org/通过这个链接可以下载apache的任何资源。话说apache真是伟大呀!
这个网页讲的真是太好了,虽然是英语:http://www.tutorialspoint.com/xml-rpc/xml_rpc_quick_guide.htm
这个网页讲的有点深:http://www.ibm.com/developerworks/cn/webservices/1211_zhusy_rpc/
二.python实现
python实现参见此博客,此人是一代神牛,更何况是个女的。http://blog.csdn.net/abcjennifer/article/details/38393185
创建服务器,构造方法,注册方法
from SimpleXMLRPCServer import SimpleXMLRPCServer
def is_even(n):
return n%2 == 0
server = SimpleXMLRPCServer(("localhost", 8000))#确定URL和端口
print "Listening on port 8000..."
server.register_function(is_even, "is_even") #注册is_even函数
server.serve_forever()#启动服务器,并使其对这个连接可用
创建客户端,请求方法
import xmlrpclib
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
print "3 is even: %s" % str(proxy.is_even(3))#客户端调用XML-RPC函数
print "100 is even: %s" % str(proxy.is_even(100))
三.xmlrpc++是C++版的xml-rpc接口实现
四.java大法好,一统天下
apache的XML-RPC似乎发生了很大改变,变得极为严谨。
下面的代码分为服务器端和客户端两部分,故意用了用一句话编程。读之给人一种一气呵成,气贯长虹之感。功能是:服务器端有两个函数add和sub,客户端请求其中之一并传入两个int类型的参数,返回int类型的结果并输出。
服务器端代码:
class RPCServer {
public static void main(String[] args) throws IOException {
WebServer server = new WebServer(8080);
server.getXmlRpcServer().setHandlerMapping(new XmlRpcHandlerMapping() {
@Override
public XmlRpcHandler getHandler(String handlerName)
throws XmlRpcNoSuchHandlerException, XmlRpcException {
switch (handlerName) {
case "add" :
return new XmlRpcHandler() {
@Override
public Object execute(XmlRpcRequest arg)
throws XmlRpcException {
int x = (int) arg.getParameter(0),
y = (int) arg.getParameter(1);
return x + y;
}
};
case "sub" :
return new XmlRpcHandler() {
@Override
public Object execute(XmlRpcRequest arg)
throws XmlRpcException {
int x = (int) arg.getParameter(0),
y = (int) arg.getParameter(1);
return x - y;
}
};
default :
return null;
}
}
});
server.start();
}
}
下面是客户端代码
class RPCClient {
public static void main(String[] args) throws XmlRpcException {
XmlRpcClient client = new XmlRpcClient();
int ans = (int) client.execute(new XmlRpcRequest() {
int x = 3, y = 6;
@Override
public int getParameterCount() {
return 2;
}
@Override
public Object getParameter(int x) {
if (x == 0)
return this.x;
else
return this.y;
}
@Override
public String getMethodName() {
return "add";
}
@Override
public XmlRpcRequestConfig getConfig() {
XmlRpcClientConfigImpl x = new XmlRpcClientConfigImpl();
try {
x.setServerURL(new URL("http://localhost:8080"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
return x;
}
});
System.out.println(ans);
}
}
五.关于metaweblog协议
这个协议应用了XML-RPC,是各大博客统一支持的接口,供用户使用。百度metaweblog会出来一堆的,用这几个函数接口就足以访问博客了。下面以博客园的接口为例简要介绍:
三个大类九大函数七大结构体:
三个大类是谁?blogger(2个函数),metaWeblog(6个函数),wp(1个函数)
九大函数是谁?
•blogger.deletePost 删除随笔
•blogger.getUsersBlogs获取我的博客,我可能有多个博客
•metaWeblog.editPost修改随笔
•metaWeblog.getCategories获取随笔类别
•metaWeblog.getPost获取随笔
•metaWeblog.getRecentPosts获取最近随笔
•metaWeblog.newMediaObject新建多媒体对象,其实就是上传文件,在博客园里面只能上传图片,返回图片的url,这样这文章中就可以使用这个url了。
•metaWeblog.newPost新建随笔
•wp.newCategory这个函数似乎是博客园独有的,可以添加分类
这九大函数根据名称就能看出来分为三大家子,其中wp这一家只有一个”新建类别“函数,blogger这一家有弟兄俩,这两个函数都需要appKey,这appKey其实不是必要的,博客园中用不到;metaWeblog是最主要的,包括对随笔的增改查三种操作,其中查又分为两种操作:根据postid查询博客;查询最近博客。metaWeblog还包括一个上传文件操作。
七个结构体:
BlogInfo描述博客的id,url,博客名等信息;
Post描述随笔的发布日期,题目,类别,具体内容等信息;
CategoryInfo描述类别信息;
FileData描述如何传输文件,包括文件名及文件内容,其中文件内容采用base64编码,上传到服务器后返回一个url,FileData有三个成员变量
bits:文件内容,byte[]类型,推荐使用java.nio一句话的事:Files.readAllBytes(Paths.get("shq.jpg")):byte[]
name:文件名,后缀必须是\.jpg|\.gif|\.png|\.jpeg之一,也就是说只允许上传图片
type:文件类型(不需要设置,如果设置了,容易出错,返回500服务器内部错误),服务器自己会解析什么类型,无须告知。
URLData只包含一项URL,写的博客是一个html,里面嵌套着图片,图片以结构体的形式FileData用metaWeblog.newMediaObject上传到服务器,返回一个url,这样就可以在html中使用这个url了。
Enclosure包括长度,类型,URL三项。
Source包含url及名称两项
以上内容在博客园里可以找到:
方式一:管理>设置选项底部
方式二:在我的首页,ctrl+u查看网页源代码,<header>里面有一个RSD(really simple discovery),进入这个链接,它是一个XML,里面包含了博客园的weblog入口。
顺道说说RSS和RSD。
RSS:really simple syndication简易信息聚合,为了人们快速获取有效信息。
RSD:really simple discovery简易入口,为了人们快速找到网络服务入口。
这两者都是特定领域协议。
六.XML-RPC的数据类型
是不是顺序有点乱,觉得应该把这一部分放在前面。其实都行,学习就需要回环往复,由深入浅又由浅入深,没有必要按部就班,只要会了就行。
6种基本数据类型,2种组合数据类型。XML-RPC说:一切皆value。所以一共有八种value。
<value><int>2323</int></value>
<value><double>23.23<double></value>
<value><boolean>1或者0</boolean></value>
<value><string>weidiao</string></value>
<value><dateTime>20021125T02:20:04</dateTime></value>格式显而易见:yyyyMMddThh:mm:ss
<value><base64>ASDFASD9823</base64></value>将任意二进制数据转换成base64编码方式。
<value><array><data>里面可以放多个value</data></array></value>我认为data这个标签有点多余
<value><struct>这里可以放多个member,每一个member都是一个name-value-pair</struct></value>
Basic Data Types in XML-RPC
Type |
Value |
Examples |
int or i4 |
32-bit integers between - 2,147,483,648 and 2,147,483,647. |
<int>27</int> <i4>27</i4> |
double |
64-bit floating-point numbers |
<double>27.31415</double> <double>-1.1465</double> |
Boolean |
true (1) or false (0) |
<boolean>1</boolean> <boolean>0</boolean> |
string |
ASCII text, though many implementations support Unicode |
<string>Hello</string> <string>bonkers! @</string> |
dateTime.iso8601 |
Dates in ISO8601 format: CCYYMMDDTHH:MM:SS |
<dateTime.iso8601> 20021125T02:20:04 </dateTime.iso8601> <dateTime.iso8601> 20020104T17:27:30 </dateTime.iso8601> |
base64 |
Binary information encoded as Base 64, as defined in RFC 2045 |
<base64>SGVsbG8sIFdvcmxkIQ==</base64> |
两种组合数据类型:数组和结构体。数组表示了一种序列化信息,数组可以包含多种数据类型;结构体其实相当于映射,是键值对,是属性集,是关联数组。
基本数据类型在xml中表示如下:<value><type>xxxx</type></value>。除了string类型可以省略<type>标签外,其余五种基本数据类型必须明确注明数据类型(这一点就不要记了,统一处理,<value></value>必须注明数据类型)。
<value>
<array>
<data>
<value><string>This </string></value>
<value><string>is </string></value>
<value><string>an </string></value>
<value><string>array.</string></value>
</data>
</array>
</value>
数组中的元素类型可以有多种:
<value>
<array>
<data>
<value><int>7</int></value>
<value><string>dfdfdf</string></value>
<value><int>-91</int></value>
<value><int>42</int></value>
</data>
</array>
</value>
数组也可以嵌套的,很显然数组相当于value的一种
<value>
<array>
<data>
<value>
<array>
<data>
<value><int>10</int></value>
<value><int>20</int></value>
<value><int>30</int></value>
</data>
</array>
</value>
<value>
<array>
<data>
<value><int>15</int></value>
<value><int>25</int></value>
<value><int>35</int></value>
</data>
</array>
</value>
</data>
</array>
</value>
结构体的长相是这样的:
<value>
<struct>
<member>
<name>givenName</name>
<value><string>Joseph</string></value>
</member>
<member>
<name>familyName</name>
<value><string>DiNardo</string></value>
</member>
<member>
<name>age</name>
<value><int>27</int></value>
</member>
</struct>
</value>
七.发出请求
请求的格式是http请求头部+xml的具体数据内容,通过post方式发送到服务器。
其中xml内容包括两大部分:方法名及参数,一旦进入<param></param>标签,就跟上面那些数据类型一样一样的了。
<?xml version="1.0"?>
<methodCall>
<methodName>circleArea</methodName>
<params>
<param>
<value><double>2.41</double></value>
</param>
</params>
</methodCall>
八.回复的格式
包括两部分:http头部+xml具体内容,跟发送时没多大区别。如你所见,既然有http头部,那就完全可以保存cookie。
HTTP/1.1 200 OK
Date: Sat, 06 Oct 2001 23:20:04 GMT
Server: Apache.1.3.12 (Unix)
Connection: close
Content-Type: text/xml
Content-Length: 124
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><double>18.24668429131</double></value>
</param>
</params>
</methodResponse>
谁又能保证回复是一定正确的呢?服务器把错误信息反馈给用户.
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>code</name>
<value><int>26</int></value>
</member>
<member>
<name>message</name>
<value><string>No such method!</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
既然知道了发送和接受的数据格式,那么我们完全可以自己实现这个XML-RPC协议,不就是向服务器post字符串吗?post的时候有多种方式,可以同步可以异步,可以用原生的URLConnection也可以用封装过的HTTPClient。
于是问题转化为对xml串的生成和解析。xml的生成和解析也有很多库。完全可以自主开发出一套XML-RPC库。
九.接下来看什么
WSDL网络服务描述语言:基于XML描述了web服务的功能,消息格式以及协议细节.
SOAP:基于XML,用于程序之间通过http进行交流
十.内省方法
introspect一个好的事物必然能够系统地告诉人们它的一切,而不是藏着掖着。任何好的开源组件都必然对应详尽的文档。XML-RPC规定了三个保留方法用来内省服务器。什么叫内省(xing),就是朝里看,对里面进行探测。比如,根据数据库中的表自动生成实体类(PO,persistent object)叫内省;在fastjson中把javaBean映射成map对象,需要探知Bean中的全部属性和get,set方法,这也叫内省;使用XML-RPC时,调用这三个方法,就可以对服务器提供的可用方法有一个整体的认识。人类都有一种感觉:如果对一样事物没有全局的把控,就不踏实。其实能够在这种不踏实的感觉下勇猛前行者,最终才能够变得踏实,要有一种反复咀嚼的精神。system.listMethods 无参函数,返回全部方法system.methodSignature 传入函数名称system.methodHelp 传入函数名称第一个函数,返回可用方法列表;第二个函数,返回方法签名;第三个函数返回函数详情。至于返回值是什么类型的,可以通过java中的Object#getClass() 反射得到类型名称。
十一.XML-RPC的替代者
hessian基于二进制传递数据,速度快,但跨平台性比不上纯字符串格式的快.
JSON-RPC基于json串传递数据