今天寫完周報後, 花了一整天把 Telnet Client 程式物件化, 到下班前終於執行成功, 搞定. 我不把它寫進 JT 類別, 因為那很彆扭, 而且也不是一般常用的工具, 應寫成獨立類別為宜, 為了簡單起見, 我將其命名為 Telnet.java, 改寫自上一篇文章 :
# Java 的 Telnet 實作 (續)
Telnet.java
import java.io.*;
import java.net.*;
public class Telnet {
Socket socket;
BufferedInputStream in;
PrintWriter out;
public boolean connect(String host) {
return connect(host,23);
}
public boolean connect(String host,int port) {
try {
socket=new Socket(host, port);
socket.setKeepAlive(true);
in=new BufferedInputStream(socket.getInputStream());
out=new PrintWriter(socket.getOutputStream(),true);
return true;
}
catch (Exception e) {e.printStackTrace();return false;}
}
public boolean login(String usr, String pwd) {
try {
String res=readUntil("Enter User Name");
if (res!=null) {
res=readUntil(">");
if (res != null) {
send(usr);
Thread.sleep(500);
res=readUntil("Enter Password");
if (res != null) {
send(pwd, false);
Thread.sleep(500);
res=readUntil(">");
if (res != null) {return true;}
}
}
}
return false;
}
catch(Exception e) {e.printStackTrace();return false;}
}
public void send(String command) {
send(command, true);
}
public void send(String command, boolean echo) {
try {
out.println(command + "\n");
out.flush();
if (echo) {System.out.println(command);}
}
catch (Exception e) {e.printStackTrace();}
}
public String readUntil(String pattern) {
try {
char lastChar=pattern.charAt(pattern.length()-1);
StringBuffer sb=new StringBuffer();
char ch=(char)in.read();
while(true) {
System.out.print(ch);
sb.append(ch);
if (ch==lastChar && sb.toString().endsWith(pattern)) {
return sb.toString();
}
ch=(char)in.read();
}
}
catch(Exception e) {e.printStackTrace();}
return null;
}
public void disconnect() {
try {in.close();out.close();socket.close();}
catch(Exception e) {e.printStackTrace();}
}
}
此 Telnet 類別不是可以泛用的類別, 因為其中的 login() 方法乃是針對公司某主機所特製, 如果是另外一台 Telnet 伺服主機, 其登入情況不同, 必須另行撰寫, 這樣好像失去寫進類別的意義咧. 但先求有再求好, 以後再來看看是否能一般化吧.
編譯後放在同一目錄下, 接著就可以使用它來連線了, 測試程式如下 :
public class test12 {
public static void main(String[] args) {
Telnet client=new Telnet();
if (client.connect("aa.bbb.cc.dd",23)) { //連線主機
String usr="asabulu";
String pwd="blabla";
if (client.login(usr,pwd)) { //登入主機
client.send("lis table users all;"); //傳送指令
String res=client.readUntil("BOTTOM"); //取得主機回應資料
}
else {System.out.println("login failed!");}
}
else {System.out.println("connect failed!");}
client.disconnect();
}
}
執行後成功列印出所需資料. 下一步要改成將主機回應資料儲存至指定檔案. 其次 login() 方法應該自 Telnet.java 中移出到應用程式中來, 因為它會因伺服器不同而需改寫. (2014-05-02)
2014-05-05 補充 :
今天改寫上周完成的 Telnet.java 類別如下 :
import java.io.*;
import java.net.*;
public class Telnet {
Socket socket;
BufferedInputStream in;
PrintWriter out;
public boolean connect(String host) {
return connect(host,23);
}
public boolean connect(String host,int port) {
try {
socket=new Socket(host, port);
socket.setKeepAlive(true);
in=new BufferedInputStream(socket.getInputStream());
out=new PrintWriter(socket.getOutputStream(),true);
return true;
}
catch (Exception e) {e.printStackTrace();return false;}
}
public void send(String command) {
send(command, true);
}
public void send(String command, boolean echo) {
try {
out.println(command + "\n");
out.flush();
if (echo) {System.out.println(command);}
}
catch (Exception e) {e.printStackTrace();}
}
public String readUntil(String pattern) {
return readUntil(pattern,100000);
}
public String readUntil(String pattern,int maxLoops) {
try {
char lastChar=pattern.charAt(pattern.length()-1);
StringBuffer sb=new StringBuffer();
char ch=(char)in.read();
int cnt=0;
while(true) {
System.out.print(ch);
sb.append(ch);
if (ch==lastChar && sb.toString().endsWith(pattern)) {
return sb.toString();
}
ch=(char)in.read();
if (++cnt > maxLoops) {break;}
}
}
catch(Exception e) {e.printStackTrace();}
return null;
}
public void wait(int ms) {
try {Thread.sleep(ms);}
catch(Exception e) {e.printStackTrace();}
}
public void disconnect() {
try {in.close();out.close();socket.close();}
catch(Exception e) {e.printStackTrace();}
}
}
主要是加入 wait() 方法, readUntil() 加入無限迴圈控制, 以及將 login 移出. 應用程式如下 :
public class fetchA {
Telnet client;
public static void main(String[] args) {
new fetchA();
}
public fetchA() {
StringBuffer sb=new StringBuffer(); //儲存擷取之資料
client=new Telnet();
if (client.connect("aa.bbb.cc.dd",23)) {
String usr="asabulu";
String pwd="blabla";
String res=login(usr,pwd);
if (res != null) {
sb.append(res);
client.send("LIST TABLE USERS ALL;");
res=client.readUntil("BOTTOM");
if (res != null) {
sb.append(res);
res=logout();
sb.append(res);
}
}
else {System.out.println("login failed!");}
}
else {System.out.println("connect failed!");}
JT.writeFile("test.log",sb.toString()); //擷取之資料寫入檔案
client.disconnect();
}
public String login(String usr, String pwd) {
String res=client.readUntil("Enter User Name");
if (res!=null) {
res=client.readUntil(">");
if (res != null) {
client.send(usr);
client.wait(500);
res=client.readUntil("Enter Password");
if (res != null) {
client.send(pwd, false);
client.wait(500);
res=client.readUntil(">");
if (res != null) {return res;}
}
}
}
return null;
}
public String logout() {
/*
>LOGOUT
BYE BYE
Asabulu Logged out on 2014/05/05 at 11:18:29.
*/
StringBuffer sb=new StringBuffer();
String res=client.readUntil(">");
sb.append(res);
if (res!=null) {
client.send("LOGOUT;");
res=client.readUntil(".");
if (res != null) {
sb.append(res);
return sb.toString();
}
}
return null;
}
}
這個 fetchA 程式是專為公司的 A 主機而寫, 每一台主機的登入方式都不一樣, 所以必須移出 Telnet 類別加以客製化, 分別撰寫 login() 與 logout() 方法. 此處 A 主機 LOGOUT 後會輸出登出時間, 為了保留完整資訊, readUntil() 讀取到日期後面的小數點時, 表示已經輸出登出資訊了.
沒有留言:
張貼留言