2014年5月2日 星期五

Java 的 Telnet 實作 (續)

昨晚搞定 Telnet 連線程式後, 早上到公司立刻改寫以便測試是否能連線某主機, 然後遠端下指令後, 取得系統資訊, 經過剖析處理後放入資料庫以方便營運管理. 改寫的程式參考前篇文章 :

Java 的 Telnet 實作

此主機連線後會先要求輸入帳號與密碼認證 :

Enter User Name
>asabulu

Enter Password
>********

因此這裡必須持續攔截輸入串流是否出現 "Enter User Name" 以及 ">", 是的話就將帳號寫入輸出串流, 然後再攔截輸入串流是否出現 "Enter Password" 以及 ">", 是的話就將密碼寫入輸出串流, 這樣就可以登入系統, 可以下達指令了, 例如顯示某資料表內容. 此系統在顯示結束時會以 "BOTTOM" 字串結尾, 因此可用來辨認下達一個指令後, 伺服主機回應的資料是否列印完畢, 達成同步的目的.

之前使用 Javascrip 去呼叫 Putty 做 Telnet 連線取得資料的做法, 因為 Javascript 無法取得輸出入串流, 因此無法與主機同步, 下達指令後還要預估資料要花多少時間才會列印完畢, 然後安插適當的 wait 秒數, 才能下達下一個指令, 否則不同資料表的內容就會前後穿插列印, 導致後續剖析程式分析錯誤. 這種不同步的通訊方式現在看起來還真可笑, 但卻成功運作了兩年之久.



import java.io.*;
import java.net.*;
public class test9_1 {
  static Socket socket;
  static BufferedInputStream bis;
  static BufferedReader r;
  static PrintWriter w;
  public static void main(String[] args) {
    try {
      String host="aa.bbb.cc.dd";  //Telnet 伺服主機
      int port=23;
      String usr="asabulu\n";  //帳號
      String pwd="blabla\n";  //密碼
      if (connect(host,port,usr,pwd)) {System.out.println("connected");}
      else {System.out.println("not connected");}
      socket.close();      
      }
    catch (Exception e) {e.printStackTrace();}
    }
  public static boolean connect(String host,String usr,String pwd) {
    return connect(host,23,usr,pwd);  //預設 port 23
    }
  public static boolean connect(String host,int port,String usr,String pwd) {
    try {
      socket=new Socket(host, port);
      socket.setKeepAlive(true);
      bis=new BufferedInputStream(socket.getInputStream());
      w=new PrintWriter(socket.getOutputStream(),true);
      if (readUntil("Enter User Name")==null) {return false;}
      if (readUntil(">")==null) {return false;}
      Thread.sleep(2000);
      send(usr);
      Thread.sleep(500);
      if (readUntil("Enter Password")==null) {return false;}
      if (readUntil(">")==null) {return false;}
      Thread.sleep(500);
      send(pwd, false);  //不於本機顯示密碼
      Thread.sleep(500);
      if (readUntil(">")==null) {return false;}
      Thread.sleep(2000);
      send("lis table aaa;");
      if (readUntil("BOTTOM")==null) {return false;}
      Thread.sleep(5000);
      return true; // connect OK
      }
    catch (Exception e) {e.printStackTrace();return false;}
    }
  public static void send(String command) {
    send(command, true);  //預設本機顯示應傳送之命令
    }
  public static void send(String command, boolean echo) {  //傳送指令
    try {
      w.println(command);
      w.flush();
      if (echo) {System.out.println(command);}  //顯示所傳送之指令      
      }
    catch (Exception e) {e.printStackTrace();}
    }
  public static String readUntil(String pattern) {
    try {
      char lastChar=pattern.charAt(pattern.length()-1);   //紀錄要攔截的最後一個字元
      StringBuffer sb=new StringBuffer();  //暫存輸入串流讀入之內容
      char ch=(char)bis.read();  //一次讀取一個字元  
      while(true) {   //無限迴圈
        System.out.print(ch);  //顯示讀入之字元
        sb.append(ch);  //讀入之字元存入緩衝器
        if (ch==lastChar && sb.toString().endsWith(pattern)) {
          return sb.toString();  //找到目標字串, 傳回讀取之串流字串 (可用來存檔)
          }    
        ch=(char)bis.read(); /續讀
        }
      }
    catch(Exception e) {e.printStackTrace();}
    return null;
    }
  }

實際測試可成功登入主機並下達顯示資料表之命令. 此處我還沒有處理主機傳回資料的存檔問題, 雖然這是我真正的目的, 但我想把程式改成物件化與多緒執行再來.




沒有留言 :