有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類要簡單不少。