返回信息流例子:远端调用,允许客户端调用服务器上的函数
服务器端:
import xmlrpc.server
svr = xmlrpc.server.SimpleXMLRPCServer(("",8000))
def greet(name):
return "Hello, {}!".format(name)
svr.register_function(greet)
svr.serve_forever()
客户端:
import xmlrpc.client
c = xmlrpc.client.Server("http://localhost:8000")
print(c.greet("world"))
难点在哪里?
服务器和客户端都是高度动态的。
服务器端可以把任何函数注册成远程调用的函数,然后直接用名字调用它。
客户端的Server(其实是个proxy)对象可以使用任何方法而不需要定义。其实这个proxy在创建的时候并不知道服务器接受哪些方法,而是当调用这个proxy的方法的时候,发送一个请求,然后自动解码响应并返回。
Java里这样做很难。Java的方法调用都是静态的:比如如果有c.greet这样的调用,编译器就要检查:“这个类有没有greet这个方法?”当然这是检查不出来的,有没有greet方法是由服务器决定的。因此,Java里能做到的就只有这样:
// 服务器端
XMLRPCServer svr = new XMLRPCServer(8000);
svr.registerHandler(new XMLRPCHandler() {
public void handle(XMLRPCRequest req, XMLRPCResponse resp) {
if (req.name.equals("greet")) {
String arg = (String)req.getArgs().get(0);
String result = someLocalObject.greet(arg);
resp.returnValue(result);
}
}
});
// 客户端
ServerProxy s = new ServerProxy("localhost", 8000);
String retVal = (String)s.call("greet", new Object[] {"world"});
System.out.println(retVal);
注意到,客户端的s.call把远端方法的名字传入call方法了,而不是直接调用greet方法。
“可是Java有反射!!!!!!!”
嗯,没错。可以用java.lang.Proxy类来实现这种反射式的动态编程。https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
这是一条镜像帖。来源:北邮人论坛 / python / #5815同步于 2015/3/26
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Python机器人发帖
贴个python很容易但java很难做的事
nuanyangyang
2015/3/26镜像同步25 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 reverland 的大作中提到: 】
: 可是java有反射!
嗯。是的。来一发:下面的程序只是部分实现xmlrpc协议,可以和楼主的python服务器通信。重点是那个Proxy对象。XML什么的大家都会解析,不说了。
package cn.byr.nuanyangyang.xmlrpc;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
interface Greeter {
String greet(String name);
}
public class XMLRPCClient {
private String url;
public XMLRPCClient(String url) {
this.url = url;
}
private XMLOutputFactory xof = XMLOutputFactory.newFactory();
private XMLInputFactory xif = XMLInputFactory.newFactory();
class ProxyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLStreamWriter w = xof.createXMLStreamWriter(baos);
w.writeStartDocument();
w.writeStartElement("methodCall");
w.writeStartElement("methodName");
w.writeCharacters(methodName);
w.writeEndElement(); // methodName
w.writeStartElement("params");
for (Object arg : args) {
w.writeStartElement("param");
if (arg instanceof Integer) {
w.writeStartElement("value");
w.writeStartElement("int");
w.writeCharacters(arg.toString());
w.writeEndElement(); // int
w.writeEndElement();// value
} else if (arg instanceof String) {
w.writeStartElement("value");
w.writeStartElement("string");
w.writeCharacters(arg.toString());
w.writeEndElement();// string
w.writeEndElement();// value
} else {
throw new RuntimeException("Arg type not implemented");
}
w.writeEndElement();
}
w.writeEndElement(); // params
w.writeEndElement(); // methodCall
w.writeEndDocument();
w.flush();
w.close();
byte[] bary = baos.toByteArray();
URL url = new URL(XMLRPCClient.this.url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "text/xml");
conn.addRequestProperty("Content-Length",
Integer.toString(bary.length));
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
try (OutputStream os = conn.getOutputStream()) {
os.write(bary);
}
int rc = conn.getResponseCode();
if (rc != 200) {
throw new RuntimeException("Server did not respond 200: " + rc);
}
try (InputStream is = conn.getInputStream()) {
XMLStreamReader r = xif.createXMLStreamReader(is);
while (r.hasNext()) {
r.nextTag();
if (r.getLocalName().equals("value")) {
r.nextTag();
if (r.getLocalName().equals("int")
|| r.getLocalName().equals("i4")) {
String txt = r.getElementText();
return Integer.valueOf(txt);
} else if (r.getLocalName().equals("string")) {
String txt = r.getElementText();
return txt;
} else {
throw new RuntimeException(
"Return type not supported: "
+ r.getLocalName());
}
}
}
throw new RuntimeException("Return value not found");
}
}
}
private ProxyInvocationHandler handler = new ProxyInvocationHandler();
public <T> T getServerProxy(Class<T> cls) {
Object proxy = Proxy.newProxyInstance(
XMLRPCClient.class.getClassLoader(), new Class<?>[] { cls },
handler);
return cls.cast(proxy);
}
public static void main(String[] args) throws Exception {
XMLRPCClient c = new XMLRPCClient("http://localhost:8000/");
Greeter remoteGreeter = c.getServerProxy(Greeter.class);
String resp = remoteGreeter.greet("Java");
System.out.println(resp);
}
}
【 在 inaadversity 的大作中提到: 】
: java 代码一写就是一坨
有现有的基于proxy的库,比如redstone xmlrpc client。用户只要写那个接口以及main里的部分即可。
来自「北邮人论坛手机版」