关于telnet协议的研究以及用java进行封装实现自己的telnet客户端

来源:互联网 发布:淘宝宝贝详情宽度 编辑:程序博客网 时间:2024/05/21 13:04

          最近在做一个远程控制的模块,其中用到了telnet协议,开始用的是apache-net包的telnetclient,但发现问题不少,比较慢,还有就是判断是否read完毕的问题。后来经过讨论打算实现自己的telnet,于是网址打罗了一番,找了一个,但是bug也不少,就开始封装。具体的telnet我已经发过2篇文章了,这里再发布一个深化封装的telnet实现。

仅供参考,可以在windows和linux上运行。

package baby.net.base;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetSocketAddress;import java.net.Socket;import java.util.ArrayList;import org.apache.log4j.Logger;/** * telnet 基本连接类 *  * @description * @author weichaofan * @date 2013年10月25日 */public class TelnetBase {private static final byte SB = (byte) 250;// 子选项开始private static final byte SE = (byte) 240;// 子选项结束private static final byte WILL = (byte) 251;// 选项协商private static final byte WONT = (byte) 252;// 选项协商private static final byte DO = (byte) 253;// 选项协商private static final byte DONT = (byte) 254;// 选项协商private static final byte IAC = (byte) 255;// 数据字节255private static final byte ECHO = (byte) 1;// 回显private static final byte IS = (byte) 0;// 是private static final byte SUPPRESS = (byte) 3;// 抑制继续进行private static final byte TT = (byte) 24;// 终端类型private InputStream is;private OutputStream os;private Socket client;private byte[] readBuffer = new byte[20 * 1024];private int miniReadIntervalMillSec = 3000;// 最短read阻塞间隔时间-毫秒private int connectTimeout = 1000;// 连接超时时间private int maxReadTimeout = 5000;public static String[] failTags = { "Failed", "fail", "incorrect" };public static String[] loginTags = { "$", "#", ">", "ogin", "@" };public static String[] commondEndTags= { "$", "#", ">"};public static String[] allTags = { "Failed", "fail", "incorrect", "$", "#",">", "ogin", "@" };private String ip;private int port = 23;Logger logger = Logger.getLogger(getClass());/** *  * 打开telnet连接 *  * @param ip * @param port *            23 *  * @return *  * @throws CmdException */public TelnetBase(String ip) {this(ip, 23);}/** *  * 打开telnet连接 *  * @param ip * @param port * @return * @throws CmdException */public TelnetBase(String ip, int port) {this.ip = ip;this.port = port;}/** * 连接 *  * @return * @throws Exception */public String connect() throws Exception {try {client = new Socket();client.connect(new InetSocketAddress(ip, port), connectTimeout);client.setSoTimeout(miniReadIntervalMillSec);// 设置is的read方法阻塞时间is = client.getInputStream();os = client.getOutputStream();} catch (Exception e) {this.close();throw new Exception(e);}return readKeyWords("ogin:");}/** *  * 读取回显,并进行telnet协商 *  * @return *  * @throws IOException */public String recieveEcho() throws IOException {int len = is.read(this.readBuffer);ArrayList<Byte> bsList = new ArrayList<Byte>();ArrayList<Byte> cmdList = new ArrayList<Byte>();for (int i = 0; i < len; i++) {int b = this.readBuffer[i] & 0xff;// &0xff是为了防止byte的255溢出,java中byte的取值是-128~127if (b != 255) {if (b == '\n' || b == '\0') {// NVT中行结束符以'\r\n'表示,回车以'\r\0表示'continue;}bsList.add((byte) b);continue;}cmdList.add(IAC);switch (this.readBuffer[++i] & 0xff) {case 251:// 服务器想激活某选项if ((readBuffer[++i] & 0xff) == 1) {// 同意回显cmdList.add(DO);cmdList.add(ECHO);} else if ((readBuffer[i] & 0xff) == 3) {// 同意抑制继续执行cmdList.add(DO);cmdList.add(SUPPRESS);// cmdList.add(GA);} else {// 不同意其他类型协商cmdList.add(DONT);cmdList.add(readBuffer[i]);}break;case 253:// 服务器想让客户端发起激活某选项if ((readBuffer[++i] & 0xff) == 24) {// 终端类型cmdList.add(WONT);// 同意激活终端类型协商cmdList.add(TT);} else if ((readBuffer[i] & 0xff) == 1) {cmdList.add(WILL);cmdList.add(ECHO);} else {cmdList.add(WONT);// 不同意其他类型协商cmdList.add(readBuffer[i]);}break;case 250:// 子选项开始cmdList.add(SB);if ((readBuffer[++i] & 0xff) == 24&& (readBuffer[++i] & 0xff) == 1) {// 发送你的终端类型cmdList.add(TT);cmdList.add(IS);// 我的终端类型是cmdList.add((byte) 'V');cmdList.add((byte) 'T');cmdList.add((byte) '1');cmdList.add((byte) '0');cmdList.add((byte) '0');}break;case 240:// 子选项结束cmdList.add(SE);break;case 252:// 必须同意cmdList.add(DONT);cmdList.add(readBuffer[++i]);break;case 254:// 必须同意cmdList.add(WONT);cmdList.add(readBuffer[++i]);break;}}// 如果有协商则向服务端发送协商选项if (cmdList.size() > 0) {byte[] writeBuffer = new byte[cmdList.size()];for (int i = 0; i < cmdList.size(); i++) {writeBuffer[i] = cmdList.get(i);}os.write(writeBuffer);}// 组织回显字符int size = bsList.size();String str = "";if (size > 0) {byte[] bs = new byte[size];for (int i = 0; i < size; i++) {bs[i] = bsList.get(i).byteValue();}str = new String(bs, "gbk");} else {// 如果是协商,则回传协商信息if (cmdList.size() > 0) {str = recieveEcho();}}//log(len, cmdList);return str;}private void log(int len, ArrayList<Byte> cmdList) {logger.debug("read===== ");for (int i = 0; i < len; i++) {logger.debug(readBuffer[i] & 0xff);logger.debug(" ");}if (cmdList.size() > 0) {logger.debug("write==== ");for (int i = 0; i < cmdList.size(); i++) {logger.debug(cmdList.get(i) & 0xff);logger.debug(" ");}}}/** * 用户名 命令中不要包括回车、换行 *  * @param cmd * @param keyWords * @return */public String sendUserName(String name) throws Exception {name += "\r\n";os.write(name.getBytes());return readKeyWords("assword");}/** * 密码 命令中不要包括回车、换行 *  * @param cmd * @param keyWords * @return */public String sendUserPwd(String pwd) throws Exception {pwd += "\r\n";os.write(pwd.getBytes());return readKeyWords(allTags);}/** * 命令中不要包括回车、换行 *  * @param cmd * @param keyWords * @return */public String sendCmd(String cmd, String... keyWords) throws Exception {return sendCmd(cmd,false,keyWords);}/** * 命令中不要包括回车、换行 *  * @param cmd * @param keyWords * @return */public String sendCmd(String cmd,boolean excludeCommandCheck, String... keyWords) throws Exception {os.write((cmd + "\r\n").getBytes());if(!excludeCommandCheck){return readKeyWords(cmd,maxReadTimeout,keyWords);}else{return readKeyWords(keyWords);}}/** * 命令中不要包括回车、换行 默认搜索条件为$、#、> *  不包含执行命令中的关键字 * @param cmd * @param keyWords * @return */public String sendCommand(String cmd) throws Exception {return sendCommand(cmd,false);}/** * 命令中不要包括回车、换行 默认搜索条件为$、#、> *  是否包含执行命令中的关键字 * @param cmd * @param keyWords * @return */public String sendCommand(String cmd,boolean excludeCommandCheck) throws Exception {os.write((cmd + "\r\n").getBytes());if(!excludeCommandCheck){return readKeyWords(cmd,maxReadTimeout,commondEndTags);}else{return readKeyWords(commondEndTags);}}/** * 命令中不要包括回车、换行 默认搜索条件为$、#、> * 不包含执行命令中的关键字 * @param cmd * @param timeOut * @param keyWords * @return */public String sendCommand(String cmd, long timeOut) throws Exception {return sendCommand(cmd,timeOut, false);}/** * 命令中不要包括回车、换行 默认搜索条件为$、#、> * 是否包含执行命令中的关键字 * @param cmd * @param timeOut * @param keyWords * @return */public String sendCommand(String cmd, long timeOut,boolean excludeCommandCheck) throws Exception {os.write((cmd + "\r\n").getBytes());if(!excludeCommandCheck){return readKeyWords(cmd,timeOut, commondEndTags);}else{return readKeyWords(timeOut, commondEndTags);}}/** * 命令中不要包括回车、换行 *  * @param cmd * @param timeOut * @param keyWords * @return */public String sendCmd(String cmd, long timeOut, String... keyWords)throws Exception {return sendCmd(cmd,false,timeOut, keyWords);}/** * 命令中不要包括回车、换行 *  * @param cmd * @param timeOut * @param keyWords * @return */public String sendCmd(String cmd, boolean excludeCommandCheck,long timeOut, String... keyWords)throws Exception {os.write((cmd + "\r\n").getBytes());if(!excludeCommandCheck){return readKeyWords(cmd,timeOut, keyWords);}else{return readKeyWords(timeOut, keyWords);}}/** *  * 关闭telnet连接 */public void close() {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (client != null) {try {client.close();} catch (IOException e) {e.printStackTrace();}}}/** *  * 读取期望值,使用默认超时时间5秒 *  * @param keyWords *  * @return */public String readKeyWords(String... keyWords) {return this.readKeyWords(maxReadTimeout, keyWords);}/** *  * 读取期望值 *  * @param timeOut *            超时时间 *  * @param keyWords *  * @return *  * @throws CmdException */public String readKeyWords(long timeOut, String... keyWords) {String rv = "";long nextTime = 0;long endTime = System.currentTimeMillis() + timeOut;do {try {String _rv = this.recieveEcho();rv += _rv;} catch (IOException e) {nextTime = endTime - System.currentTimeMillis();}} while (!this.findKeyWord(keyWords, rv) && nextTime >= 0);if (nextTime < 0)System.err.println("Read TimeOut...Echo:\n" + rv);return rv;}/** *  * 读取期望值  排除command中含有的关键字 *  * @param timeOut *            超时时间 *  * @param keyWords *  * @return *  * @throws CmdException */public String readKeyWords(String command,long timeOut, String... keyWords) {String rv = "";long nextTime = 0;long endTime = System.currentTimeMillis() + timeOut;do {try {String _rv = this.recieveEcho();rv += _rv;} catch (IOException e) {nextTime = endTime - System.currentTimeMillis();}} while (!this.findKeyWord(command,keyWords, rv) && nextTime >= 0);if (nextTime < 0)System.err.println("Read TimeOut...Echo:\n" + rv);return rv;}/** *  * 查找关键字 *  * @param keyWords *  * @param str *  * @return */public boolean findKeyWord(String[] keyWords, String str) {if (str == null || "".equals(str))return false;if (keyWords == null || keyWords.length == 0)return true;for (int i = 0; i < keyWords.length; i++) {if (str.indexOf(keyWords[i]) != -1)return true;}return false;}/** *  * 查找关键字  排除command中含有的关键字 *  * @param keyWords *  * @param str *  * @return */public boolean findKeyWord(String command,String[] keyWords, String str) {if (str == null || "".equals(str))return false;if (keyWords == null || keyWords.length == 0)return true;System.out.println(str);if(-1 != str.indexOf(command)){str=str.substring(str.indexOf(command)+command.length());for (int i = 0; i < keyWords.length; i++) {if (str.indexOf(keyWords[i]) != -1)return true;}}return false;}/** * 最短读阻塞时间 *  * @return */public int getMiniReadIntervalMillSec() {return miniReadIntervalMillSec;}public void setMiniReadIntervalMillSec(int miniReadIntervalMillSec) {this.miniReadIntervalMillSec = miniReadIntervalMillSec;}/** * 连接超时时间 *  * @return */public int getConnectTimeout() {return connectTimeout;}public void setConnectTimeout(int connectTimeout) {this.connectTimeout = connectTimeout;}/** * 最大读阻塞时间 *  * @return */public int getMaxReadTimeout() {return maxReadTimeout;}public void setMaxReadTimeout(int maxReadTimeout) {this.maxReadTimeout = maxReadTimeout;}}