近期我们的网管项目要新接进一批操作系统是HP-UX的机器,采集方式还是大家很熟悉的Telnet,通过java程序模拟发送shell命令采集获取机器的CPU使用率,内存使用率和磁盘使用率等设备的性能指标,但是使用以前采集AIX,SOLARIS平台的代码却采集不成功,程序发送密码过去,却不能拿到shell的返回,原telnet采集代码如下:
该文草草写就,谨对网上的参考文章的作者表示感谢,参考资料如下:
public class TelnetUtil {
// 重新定义TelnetUtil的日志跟踪信息
private Logger logger;
protected String host;
protected int port = 23;
private TelnetClient tc;
// 这两个需要供子类共用
protected InputStream in;
protected PrintStream out;
private Integer WAIT_TIME = 3000; // 搞长一点,修改为3秒
private static final String EOL = "\r\n";
@SuppressWarnings("unused")
private String prompt;
// 任务id
protected long taskId;
/**
* IP地址,端口号
*
* @param host
* String
* @param port
* int
*/
public TelnetUtil(String host) {
this.host = host;
}
/**
* IP地址,端口号
*
* @param host
* String
* @param port
* int
*/
public TelnetUtil(String host, int port, String prompt) {
this.prompt = prompt;
this.host = host;
this.port = port;
}
public TelnetUtil(String host, int port) {
this.host = host;
this.port = port;
}
/**
*
* @param host 地址
* @param port 端口
* @param taskId 任务id
*/
public TelnetUtil(String host,int port,Long taskId) {
this(host,port);
this.taskId = taskId;
logger = Logger.getLogger("/UTIL/TELNETUTIL/id_" + taskId,
Logger.ALL, true);
}
/**
* 初始化Telnet Client
*
* @throws InvalidTelnetOptionException
* @throws IOException
* @throws SocketException
*
* @throws Exception
*/
private void initTelnetClient() throws InvalidTelnetOptionException,
SocketException, IOException {
logger.infoT("start task id is " + taskId);
tc = new TelnetClient();
TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler(
"vt100", false, false, true, false);
EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true,
false);
SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true,
true, true);
tc.addOptionHandler(ttopt);
tc.addOptionHandler(echoopt);
tc.addOptionHandler(gaopt);
tc.setDefaultTimeout(30000);
// tc.setSoTimeout(10000);
tc.connect(host, port);
tc.setReaderThread(true);
in = tc.getInputStream();
logger.debugT("telnet " + host + ":" + port);
out = new PrintStream(tc.getOutputStream());
}
/**
* 登录服务器
*
* @param userName
* String
* @param password
* String
* @throws Exception
*/
public void login(String userName, String password) throws Exception {
if (tc == null)
initTelnetClient();
String res = getResponseAsString();
logger.debugT("be ready for send userName:" + res);
write(userName);
waiting(); // 增加等待时间
res = getResponseAsString();
logger.debugT("be ready for send password:" + res);
write(password);
logger.infoT("password: = " + password);
// waiting(); // 增加等待时间
Thread.sleep(10000);
res = getResponseAsString();
if (res.contains("incorrect")) {
throw new java.lang.Exception("UserOrPasswordError");
}
logger.debugT("be ready for send command:" + res);
}
/**
* 获取返回数据
*
* @return String
* @throws Exception
*/
private String getResponseAsString() {
/*
* int startBlock = 0; int endBlock = 0; while (true) { startBlock =
* readThread.getBlock(); waiting(); endBlock = readThread.getBlock();
* if (endBlock == startBlock) { res = readThread.getResult(); break; }
* }
*/
StringBuilder sb = new StringBuilder(1024);
byte[] buff = new byte[1024];
int ret_read = 0;
try {
do {
ret_read = in.read(buff);
if (ret_read > 0) {
sb.append(new String(buff, 0, ret_read));
}
} while (ret_read >= 0);
} catch (IOException e) {
e.printStackTrace();
// log.exception(e);
}
return sb.toString();
}
/**
* 发送命令
*
* @param command
* String
* @throws Exception
*/
public String sendCommand(String command) throws Exception {
System.out.println("send:" + command);
command = command + EOL;
out.print(command);
out.flush();
waiting(); // update by ChangPeng 2012-03-13 改为睡眠3秒,此处多睡1秒,防止输出命令后返回流的数据还未返回
String result = getResponseAsString();
logger.infoT("send command result:" + result);
return result;
}
/**
* 发送数据
*
* @param value
* String
*/
protected void write(String value) throws Exception {
out.println(value);
out.flush();
}
/**
* 发送命令后,等待500ms,至输入流中有可读数据
*
* @throws Exception
*/
private void waiting() throws Exception {
Thread.sleep(WAIT_TIME);
}
/**
* 断开连接
*
* @throws Exception
*/
public void disConnect() throws Exception {
logger.infoT("end task id is " + taskId + "disconnet");
tc.disconnect();
tc = null;
}
public static void main(String[] srgs) {
try {
TelnetUtil tu = new TelnetUtil("10.25.3.174", 22, "\r\n");
tu.login("yangran", "123456");
String res = tu
.sendCommand("cat /proc/meminfo |grep MemFree |cut -d: -f 2|awk '($1~/^[0-9]+$/) { print $1}'");
System.out.println("res:" + res);
tu.disConnect();
} catch (Exception e) {
System.out.println(e.getClass().getCanonicalName());
// e.printStackTrace();
}
}
}
采用上面的类调用login方法,却无法模拟登陆hp_ux机器,在网上查了下,原来hp-ux的采集方式和其它linux机器是不一样的,需要在out.println(value);命令之前先做一个while(true)循环,守候到TelnetClient的InputStream得到相应的prompt值,网上代码prompt值不是"#"就是">",但是在我们服务器上用secureCRT测试发现prompt是"$",参照网上的代码,前面的登陆过程果然能通过,并顺利捕获返回的shell值,但是如果有些空行,打印返回值还是有些乱码的,这个无关大局,就没予以关注了,但是输出命令却发现一个令人苦恼的问题,因为命令中含有"$",那样readUntil就会认为是prompt"$"给提前终止了,因为InputStream的read方法这个还会带出PrintStream out输出的命令原文,其中就含有"$"。经过考虑后发现一个巧妙的解决办法,在循环中记下inputStream读取的前面的char字符,因为最后的prompt之前的char必然是'\n'换行符,这个问题就顺利得到解决,代码如下(注意TelnetHPUXUtil 是继承自上面的TelnetUtil类的,有些方法是调用了上面父类的方法)。
public class TelnetHPUXUtil extends TelnetUtil {
/**
* 日志
*/
private final Logger logger;
/**
* 所有HP-UX的机器的IP数组
*/
public final static String[] HP_UX_MACHINE_IPARR = { "10.26.106.193",
"10.26.106.194", "10.26.106.195", "10.26.106.196", "10.26.106.214" };
public final static String SPECIAL_IP = "10.26.106.214";
private String tranencoding = "iso-8859-1";
private String aixencoding = "gb2312";
private TelnetClient telnet = new TelnetClient();
private char prompt = '$';
/**
* 构造函数
*
* @param host
* 服务器地址
* @param port
* 端口
* @param user
* 用户帐号
* @param password
* 用户口令
* @param taskId
* 任务ID
*/
public TelnetHPUXUtil(String host, int port, String user, Long taskId) {
super(host, port);
this.taskId = taskId;
logger = Logger.getLogger("/UTIL/TelnetHPUXUtil/id_" + taskId,
Logger.ALL, true);
if ("root".equals(user)) {
this.prompt = '#';
} else {
this.prompt = '$';
}
// 登陆
// loginHPUX(user, password);
}
/**
* 登陆HP-UX服务器
*
* @param user
* @param password
*/
public void loginHPUX(String user, String password) {
logger.infoT("start hp-ux task id is " + taskId);
try {
telnet.connect(host, port);
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
readUntil("login: ");
write(user);
readUntil("Password: ");
write(password);
readUntil(prompt + "");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读取返回的字符串
*
* @param pattern
* 结尾的字符串
* @return 返回返回的字符串
*/
private String readUntil(String pattern) {
try {
char lastChar = pattern.charAt(pattern.length() - 1);
StringBuilder sb = new StringBuilder();
char ch = (char) in.read();
while (true) {
sb.append(ch);
if (ch == lastChar) {
if (sb.toString().endsWith(pattern)) {
String temp = sb.toString();
return temp;
}
}
ch = (char) in.read();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 读取返回的字符串
*
* @param pattern
* 结尾的字符串
* @return 返回返回的字符串
*/
private String readUntilCommand(String pattern) {
try {
char lastChar = pattern.charAt(pattern.length() - 1);
StringBuilder sb = new StringBuilder();
char ch = (char) in.read();
char beforeChar = 0;
while (true) {
sb.append(ch);
if (ch == lastChar && beforeChar == '\n') {
if (sb.toString().endsWith(pattern)) {
String temp = sb.toString();
logger.infoT(new String(temp.getBytes(tranencoding),
aixencoding));
return temp;
}
}
beforeChar = ch;
ch = (char) in.read();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 发送命令
*/
public String sendCommand(String command) {
try {
write(command);
String result = readUntilCommand(prompt + "");
// logger.infoT("command result: === " + result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void disconnect() {
logger.infoT("end hp ux task id is " + taskId + "disconnet");
try {
telnet.disconnect();
telnet = null;
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// char ch = '\n';
}
}
该文草草写就,谨对网上的参考文章的作者表示感谢,参考资料如下:
http://hi.baidu.com/zhengmh/blog/item/c7199da22ed9a6afcbefd0ba.html