有4台测试机器通过是通过路由器上网的,路由器通过拨号方式上网。每隔一段时间,就会重新拨号,在其自动拨号后,IP即发生变化,必须跑到机房查看路由器的公网ip后才能进行远程连接。
最初打算在路由器后面的机器上执行tracert www.sina.com.cn 命令来找到路由器的ip,然后自动发送邮件给相关人员。 然而在测试机上执行tracert命令不能跟踪到路由ip,时间紧迫,于是想到一个比较笨的办法,去访问一些可以显示请求机器公网ip的页面,然后把页面的内容抓取下来发邮件给大家。 该程序已用java实现,但是略感复杂。周末无事,想想能否通过ruby来访问网页获取ip地址,然后java来发送邮件。下面是实践过程:
我装的JDK是1.5,因此需要首先下载以下的包:
1)下载JRUBY包,下载地址是:http://dist.codehaus.org/jruby/1.1.6/,我下载的是最新的1.1.6版本,要注意的是一定要下载jruby-complete-1.1.6.jar包,这个完整的包里才有依赖的一些.rb文件
2) 下载JSR 223相关包,下载地址是:http://www.jcp.org/en/jsr/detail?id=223,
下载最新的发布版本,在这个包里有script-api.jar(JSR 223的实现包)、script-js.jar(Rhino的engine实现)和js.jar(Rhino)三个jar文件,都需要加入classhpath。注意:如果你使用的是JDK 1.6,那么1.6已经集成了JSR 223,所以不需要额外引入script-api.jar和script-js.jar,js.jar还是需要引入的。三个包之间的关系是:script-api.jar是面向最终的开发者的,script-js.jar是一个代理,把最终的脚本解析转发给js.jar,包括其它脚本的支持也是这种模式,比如要对JRuby支持,也肯定有一个按规范实现的代理。
3)下载JRuby的代理,https://scripting.dev.java.net/servlets/ProjectDocumentList,文件jsr223-engines.zip里包含了各种代理,在jruby/build目录下存在jruby-engine.jar文件,加入到classpath。
4)下载一个可选的辅助jar包,因为代码中用到了StringUtils类,从apache网站下载commons-lang-2.4.jar包,也加入到classpath
编写JAVA代码:
import java.util.*;
import java.io.*;
import javax.script.*;
import com.sun.script.jruby.JRubyScriptEngineManager;
import org.apache.commons.lang.StringUtils;
import java.nio.charset.*;
public class Main
{
public static void main(String args[])
{
System.out.println("----------"+System.getProperty("file.encoding"));
long start = System.currentTimeMillis();
// 取得脚本引擎的管理器,用来获取对应的引擎,如下面的jruby
//因为安装的是JDK1.5,所以要用JRubyScriptEngineManager 代替ScriptEngine ,否者编译不通过
JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
// 设置上下文参数
Hashtable<String, String> params = new Hashtable<String, String>();
params.put("id", "testID"); // JRuby会把请求响应结果放在指定的ID中,Java代码从中获取
params.put("url", "http://www.google.cn"); // HTTP请求地址
try {
// 根据指定的名字"jruby"获取脚本引擎
ScriptEngine jrubyEngine = manager.getEngineByName("jruby");
jrubyEngine.put("params", params); // 把参数放置在上下文中
// 执行HTTPService.rb中的脚本
Object value = jrubyEngine.eval(new InputStreamReader(
Main.class.getResourceAsStream("getIP.rb"))
);
// 根据指定的ID,从引擎中提取响应结果
Object response = jrubyEngine.get(params.get("id"));
// 如果ID中没有结果,则从执行eval时的返回结果中获取
if(response == null || StringUtils.isEmpty(response.toString())) {
response = (value == null ? value : value.toString());
}
// 输出请求响应结果到控制台
//System.out.println(new String(response.toString().getBytes("utf-8"),"gbk"));
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println((System.currentTimeMillis() - start) + "ms");
}
}
注意:对以JDK1.5,要用JRubyScriptEngineManager 代替ScriptEngine ,否者编译不通过。
Ruby代码(getIP.rb):
require 'net/http'
require 'uri'
eval(
"$#{$params.get('id')}=Net::HTTP.get(URI.parse('#{$params.get('url')}'))"
);
编译java后,运行Main.java 时报错:
D:/script/javaexec/juby>java Main
----------GB18030
java.lang.IllegalArgumentException: no engine registered for: jruby
需要这样才能运行:
java -cp .;D:/open/jruby/sjp-1_0-fr-ri/script-api.jar;D:/open/jruby-1.1.6/lib/bsf.jar;D:/open/jruby/jruby-complete-1.1.6.jar;D:/open/jruby/jruby-engine.jar;D:/open/commons-lang-2.4/commons-lang-2.4.jar Main
可见使用ruby去获取页面内容仅仅三行代码即完成,比起之前写的java类要简单不少。