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

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

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

  1. package baby.net.base;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.net.InetSocketAddress;  
  7. import java.net.Socket;  
  8. import java.util.ArrayList;  
  9.   
  10. import org.apache.log4j.Logger;  
  11.   
  12. /** 
  13.  * telnet 基本连接类 
  14.  *  
  15.  * @description 
  16.  * @author weichaofan 
  17.  * @date 2013年10月25日 
  18.  */  
  19. public class TelnetBase {  
  20.     private static final byte SB = (byte) 250;// 子选项开始   
  21.     private static final byte SE = (byte) 240;// 子选项结束   
  22.     private static final byte WILL = (byte) 251;// 选项协商   
  23.     private static final byte WONT = (byte) 252;// 选项协商   
  24.     private static final byte DO = (byte) 253;// 选项协商   
  25.     private static final byte DONT = (byte) 254;// 选项协商   
  26.     private static final byte IAC = (byte) 255;// 数据字节255   
  27.     private static final byte ECHO = (byte) 1;// 回显   
  28.     private static final byte IS = (byte) 0;// 是   
  29.     private static final byte SUPPRESS = (byte) 3;// 抑制继续进行   
  30.     private static final byte TT = (byte) 24;// 终端类型   
  31.     private InputStream is;  
  32.     private OutputStream os;  
  33.     private Socket client;  
  34.     private byte[] readBuffer = new byte[20 * 1024];  
  35.     private int miniReadIntervalMillSec = 3000;// 最短read阻塞间隔时间-毫秒   
  36.     private int connectTimeout = 1000;// 连接超时时间   
  37.     private int maxReadTimeout = 5000;  
  38.   
  39.     public static String[] failTags = { "Failed", "fail", "incorrect" };  
  40.     public static String[] loginTags = { "$", "#", ">", "ogin", "@" };  
  41.     public static String[] commondEndTags= { "$", "#", ">"};  
  42.     public static String[] allTags = { "Failed", "fail", "incorrect", "$", "#",  
  43.             ">", "ogin", "@" };  
  44.   
  45.     private String ip;  
  46.     private int port = 23;  
  47.   
  48.     Logger logger = Logger.getLogger(getClass());  
  49.   
  50.     /** 
  51.      *  
  52.      * 打开telnet连接 
  53.      *  
  54.      * @param ip 
  55.      * @param port 
  56.      *            23 
  57.      *  
  58.      * @return 
  59.      *  
  60.      * @throws CmdException 
  61.      */  
  62.   
  63.     public TelnetBase(String ip) {  
  64.   
  65.         this(ip, 23);  
  66.   
  67.     }  
  68.   
  69.     /** 
  70.      *  
  71.      * 打开telnet连接 
  72.      *  
  73.      * @param ip 
  74.      * @param port 
  75.      * @return 
  76.      * @throws CmdException 
  77.      */  
  78.   
  79.     public TelnetBase(String ip, int port) {  
  80.         this.ip = ip;  
  81.         this.port = port;  
  82.     }  
  83.   
  84.     /** 
  85.      * 连接 
  86.      *  
  87.      * @return 
  88.      * @throws Exception 
  89.      */  
  90.     public String connect() throws Exception {  
  91.         try {  
  92.   
  93.             client = new Socket();  
  94.             client.connect(new InetSocketAddress(ip, port), connectTimeout);  
  95.             client.setSoTimeout(miniReadIntervalMillSec);// 设置is的read方法阻塞时间   
  96.             is = client.getInputStream();  
  97.             os = client.getOutputStream();  
  98.         } catch (Exception e) {  
  99.             this.close();  
  100.             throw new Exception(e);  
  101.         }  
  102.         return readKeyWords("ogin:");  
  103.     }  
  104.   
  105.     /** 
  106.      *  
  107.      * 读取回显,并进行telnet协商 
  108.      *  
  109.      * @return 
  110.      *  
  111.      * @throws IOException 
  112.      */  
  113.   
  114.     public String recieveEcho() throws IOException {  
  115.   
  116.         int len = is.read(this.readBuffer);  
  117.   
  118.         ArrayList<Byte> bsList = new ArrayList<Byte>();  
  119.         ArrayList<Byte> cmdList = new ArrayList<Byte>();  
  120.         for (int i = 0; i < len; i++) {  
  121.             int b = this.readBuffer[i] & 0xff;// &0xff是为了防止byte的255溢出,java中byte的取值是-128~127   
  122.             if (b != 255) {  
  123.                 if (b == ' ' || b == '') {// NVT中行结束符以' '表示,回车以' 表示'   
  124.                     continue;  
  125.                 }  
  126.                 bsList.add((byte) b);  
  127.                 continue;  
  128.             }  
  129.             cmdList.add(IAC);  
  130.             switch (this.readBuffer[++i] & 0xff) {  
  131.             case 251:// 服务器想激活某选项   
  132.                 if ((readBuffer[++i] & 0xff) == 1) {// 同意回显   
  133.                     cmdList.add(DO);  
  134.                     cmdList.add(ECHO);  
  135.                 } else if ((readBuffer[i] & 0xff) == 3) {// 同意抑制继续执行   
  136.                     cmdList.add(DO);  
  137.                     cmdList.add(SUPPRESS);  
  138.                     // cmdList.add(GA);   
  139.                 } else {// 不同意其他类型协商   
  140.                     cmdList.add(DONT);  
  141.                     cmdList.add(readBuffer[i]);  
  142.                 }  
  143.                 break;  
  144.             case 253:// 服务器想让客户端发起激活某选项   
  145.                 if ((readBuffer[++i] & 0xff) == 24) {// 终端类型   
  146.                     cmdList.add(WONT);// 同意激活终端类型协商   
  147.                     cmdList.add(TT);  
  148.                 } else if ((readBuffer[i] & 0xff) == 1) {  
  149.                     cmdList.add(WILL);  
  150.                     cmdList.add(ECHO);  
  151.                 } else {  
  152.                     cmdList.add(WONT);// 不同意其他类型协商   
  153.                     cmdList.add(readBuffer[i]);  
  154.                 }  
  155.                 break;  
  156.             case 250:// 子选项开始   
  157.                 cmdList.add(SB);  
  158.                 if ((readBuffer[++i] & 0xff) == 24  
  159.                         && (readBuffer[++i] & 0xff) == 1) {// 发送你的终端类型   
  160.                     cmdList.add(TT);  
  161.                     cmdList.add(IS);// 我的终端类型是   
  162.                     cmdList.add((byte) 'V');  
  163.                     cmdList.add((byte) 'T');  
  164.                     cmdList.add((byte) '1');  
  165.                     cmdList.add((byte) '0');  
  166.                     cmdList.add((byte) '0');  
  167.                 }  
  168.                 break;  
  169.             case 240:// 子选项结束   
  170.                 cmdList.add(SE);  
  171.                 break;  
  172.             case 252:// 必须同意   
  173.                 cmdList.add(DONT);  
  174.                 cmdList.add(readBuffer[++i]);  
  175.                 break;  
  176.             case 254:// 必须同意   
  177.                 cmdList.add(WONT);  
  178.                 cmdList.add(readBuffer[++i]);  
  179.                 break;  
  180.             }  
  181.         }  
  182.         // 如果有协商则向服务端发送协商选项   
  183.         if (cmdList.size() > 0) {  
  184.             byte[] writeBuffer = new byte[cmdList.size()];  
  185.             for (int i = 0; i < cmdList.size(); i++) {  
  186.                 writeBuffer[i] = cmdList.get(i);  
  187.             }  
  188.             os.write(writeBuffer);  
  189.         }  
  190.   
  191.         // 组织回显字符   
  192.         int size = bsList.size();  
  193.         String str = "";  
  194.         if (size > 0) {  
  195.             byte[] bs = new byte[size];  
  196.             for (int i = 0; i < size; i++) {  
  197.                 bs[i] = bsList.get(i).byteValue();  
  198.             }  
  199.             str = new String(bs, "gbk");  
  200.         } else {  
  201.             // 如果是协商,则回传协商信息   
  202.             if (cmdList.size() > 0) {  
  203.                 str = recieveEcho();  
  204.             }  
  205.         }  
  206.     //  log(len, cmdList);   
  207.         return str;  
  208.     }  
  209.   
  210.     private void log(int len, ArrayList<Byte> cmdList) {  
  211.         logger.debug("read===== ");  
  212.         for (int i = 0; i < len; i++) {  
  213.             logger.debug(readBuffer[i] & 0xff);  
  214.             logger.debug(" ");  
  215.         }  
  216.   
  217.         if (cmdList.size() > 0) {  
  218.             logger.debug("write==== ");  
  219.             for (int i = 0; i < cmdList.size(); i++) {  
  220.                 logger.debug(cmdList.get(i) & 0xff);  
  221.                 logger.debug(" ");  
  222.             }  
  223.   
  224.         }  
  225.     }  
  226.   
  227.     /** 
  228.      * 用户名 命令中不要包括回车、换行 
  229.      *  
  230.      * @param cmd 
  231.      * @param keyWords 
  232.      * @return 
  233.      */  
  234.     public String sendUserName(String name) throws Exception {  
  235.         name += " ";  
  236.         os.write(name.getBytes());  
  237.   
  238.         return readKeyWords("assword");  
  239.     }  
  240.   
  241.     /** 
  242.      * 密码 命令中不要包括回车、换行 
  243.      *  
  244.      * @param cmd 
  245.      * @param keyWords 
  246.      * @return 
  247.      */  
  248.     public String sendUserPwd(String pwd) throws Exception {  
  249.         pwd += " ";  
  250.         os.write(pwd.getBytes());  
  251.   
  252.         return readKeyWords(allTags);  
  253.     }  
  254.   
  255.     /** 
  256.      * 命令中不要包括回车、换行 
  257.      *  
  258.      * @param cmd 
  259.      * @param keyWords 
  260.      * @return 
  261.      */  
  262.     public String sendCmd(String cmd, String... keyWords) throws Exception {  
  263.           
  264.         return sendCmd(cmd,false,keyWords);  
  265.     }  
  266.     /** 
  267.      * 命令中不要包括回车、换行 
  268.      *  
  269.      * @param cmd 
  270.      * @param keyWords 
  271.      * @return 
  272.      */  
  273.     public String sendCmd(String cmd,boolean excludeCommandCheck, String... keyWords) throws Exception {  
  274.         os.write((cmd + " ").getBytes());  
  275.           
  276.         if(!excludeCommandCheck){  
  277.             return readKeyWords(cmd,maxReadTimeout,keyWords);  
  278.         }else{  
  279.             return readKeyWords(keyWords);  
  280.         }  
  281.     }  
  282.   
  283.     /** 
  284.      * 命令中不要包括回车、换行 默认搜索条件为$、#、> 
  285.      *  不包含执行命令中的关键字 
  286.      * @param cmd 
  287.      * @param keyWords 
  288.      * @return 
  289.      */  
  290.     public String sendCommand(String cmd) throws Exception {  
  291.   
  292.         return sendCommand(cmd,false);  
  293.     }  
  294.     /** 
  295.      * 命令中不要包括回车、换行 默认搜索条件为$、#、> 
  296.      *  是否包含执行命令中的关键字 
  297.      * @param cmd 
  298.      * @param keyWords 
  299.      * @return 
  300.      */  
  301.     public String sendCommand(String cmd,boolean excludeCommandCheck) throws Exception {  
  302.           
  303.         os.write((cmd + " ").getBytes());  
  304.         if(!excludeCommandCheck){  
  305.             return readKeyWords(cmd,maxReadTimeout,commondEndTags);  
  306.         }else{  
  307.             return readKeyWords(commondEndTags);  
  308.         }  
  309.     }  
  310.   
  311.     /** 
  312.      * 命令中不要包括回车、换行 默认搜索条件为$、#、> 
  313.      * 不包含执行命令中的关键字 
  314.      * @param cmd 
  315.      * @param timeOut 
  316.      * @param keyWords 
  317.      * @return 
  318.      */  
  319.     public String sendCommand(String cmd, long timeOut) throws Exception {  
  320.           
  321.         return sendCommand(cmd,timeOut, false);  
  322.     }  
  323.     /** 
  324.      * 命令中不要包括回车、换行 默认搜索条件为$、#、> 
  325.      * 是否包含执行命令中的关键字 
  326.      * @param cmd 
  327.      * @param timeOut 
  328.      * @param keyWords 
  329.      * @return 
  330.      */  
  331.     public String sendCommand(String cmd, long timeOut,boolean excludeCommandCheck) throws Exception {  
  332.         os.write((cmd + " ").getBytes());  
  333.           
  334.         if(!excludeCommandCheck){  
  335.             return readKeyWords(cmd,timeOut, commondEndTags);  
  336.         }else{  
  337.             return readKeyWords(timeOut, commondEndTags);  
  338.         }  
  339.           
  340.     }  
  341.   
  342.     /** 
  343.      * 命令中不要包括回车、换行 
  344.      *  
  345.      * @param cmd 
  346.      * @param timeOut 
  347.      * @param keyWords 
  348.      * @return 
  349.      */  
  350.     public String sendCmd(String cmd, long timeOut, String... keyWords)  
  351.             throws Exception {  
  352.           
  353.         return sendCmd(cmd,false,timeOut, keyWords);  
  354.     }  
  355.     /** 
  356.      * 命令中不要包括回车、换行 
  357.      *  
  358.      * @param cmd 
  359.      * @param timeOut 
  360.      * @param keyWords 
  361.      * @return 
  362.      */  
  363.     public String sendCmd(String cmd, boolean excludeCommandCheck,long timeOut, String... keyWords)  
  364.             throws Exception {  
  365.         os.write((cmd + " ").getBytes());  
  366.         if(!excludeCommandCheck){  
  367.             return readKeyWords(cmd,timeOut, keyWords);  
  368.         }else{  
  369.             return readKeyWords(timeOut, keyWords);  
  370.         }  
  371.           
  372.     }  
  373.   
  374.     /** 
  375.      *  
  376.      * 关闭telnet连接 
  377.      */  
  378.   
  379.     public void close() {  
  380.         if (is != null) {  
  381.             try {  
  382.                 is.close();  
  383.             } catch (IOException e) {  
  384.                 e.printStackTrace();  
  385.             }  
  386.         }  
  387.         if (os != null) {  
  388.             try {  
  389.                 os.close();  
  390.             } catch (IOException e) {  
  391.                 e.printStackTrace();  
  392.             }  
  393.         }  
  394.         if (client != null) {  
  395.             try {  
  396.                 client.close();  
  397.             } catch (IOException e) {  
  398.                 e.printStackTrace();  
  399.             }  
  400.         }  
  401.     }  
  402.   
  403.     /** 
  404.      *  
  405.      * 读取期望值,使用默认超时时间5秒 
  406.      *  
  407.      * @param keyWords 
  408.      *  
  409.      * @return 
  410.      */  
  411.   
  412.     public String readKeyWords(String... keyWords) {  
  413.   
  414.         return this.readKeyWords(maxReadTimeout, keyWords);  
  415.   
  416.     }  
  417.   
  418.     /** 
  419.      *  
  420.      * 读取期望值 
  421.      *  
  422.      * @param timeOut 
  423.      *            超时时间 
  424.      *  
  425.      * @param keyWords 
  426.      *  
  427.      * @return 
  428.      *  
  429.      * @throws CmdException 
  430.      */  
  431.   
  432.     public String readKeyWords(long timeOut, String... keyWords) {  
  433.         String rv = "";  
  434.         long nextTime = 0;  
  435.         long endTime = System.currentTimeMillis() + timeOut;  
  436.         do {  
  437.             try {  
  438.                 String _rv = this.recieveEcho();  
  439.                 rv += _rv;  
  440.             } catch (IOException e) {  
  441.   
  442.                 nextTime = endTime - System.currentTimeMillis();  
  443.             }  
  444.         } while (!this.findKeyWord(keyWords, rv) && nextTime >= 0);  
  445.         if (nextTime < 0)  
  446.             System.err.println("Read TimeOut...Echo: " + rv);  
  447.         return rv;  
  448.   
  449.     }  
  450.     /** 
  451.      *  
  452.      * 读取期望值  排除command中含有的关键字 
  453.      *  
  454.      * @param timeOut 
  455.      *            超时时间 
  456.      *  
  457.      * @param keyWords 
  458.      *  
  459.      * @return 
  460.      *  
  461.      * @throws CmdException 
  462.      */  
  463.       
  464.     public String readKeyWords(String command,long timeOut, String... keyWords) {  
  465.         String rv = "";  
  466.         long nextTime = 0;  
  467.         long endTime = System.currentTimeMillis() + timeOut;  
  468.         do {  
  469.             try {  
  470.                 String _rv = this.recieveEcho();  
  471.                 rv += _rv;  
  472.             } catch (IOException e) {  
  473.                   
  474.                 nextTime = endTime - System.currentTimeMillis();  
  475.             }  
  476.         } while (!this.findKeyWord(command,keyWords, rv) && nextTime >= 0);  
  477.         if (nextTime < 0)  
  478.             System.err.println("Read TimeOut...Echo: " + rv);  
  479.         return rv;  
  480.           
  481.     }  
  482.   
  483.     /** 
  484.      *  
  485.      * 查找关键字 
  486.      *  
  487.      * @param keyWords 
  488.      *  
  489.      * @param str 
  490.      *  
  491.      * @return 
  492.      */  
  493.   
  494.     public boolean findKeyWord(String[] keyWords, String str) {  
  495.         if (str == null || "".equals(str))  
  496.             return false;  
  497.         if (keyWords == null || keyWords.length == 0)  
  498.             return true;  
  499.         for (int i = 0; i < keyWords.length; i++) {  
  500.             if (str.indexOf(keyWords[i]) != -1)  
  501.                 return true;  
  502.         }  
  503.         return false;  
  504.     }  
  505.     /** 
  506.      *  
  507.      * 查找关键字  排除command中含有的关键字 
  508.      *  
  509.      * @param keyWords 
  510.      *  
  511.      * @param str 
  512.      *  
  513.      * @return 
  514.      */  
  515.       
  516.     public boolean findKeyWord(String command,String[] keyWords, String str) {  
  517.         if (str == null || "".equals(str))  
  518.             return false;  
  519.         if (keyWords == null || keyWords.length == 0)  
  520.             return true;  
  521.         System.out.println(str);  
  522.         if(-1 != str.indexOf(command)){  
  523.             str=str.substring(str.indexOf(command)+command.length());  
  524.             for (int i = 0; i < keyWords.length; i++) {  
  525.                 if (str.indexOf(keyWords[i]) != -1)  
  526.                     return true;  
  527.             }  
  528.         }  
  529.           
  530.           
  531.         return false;  
  532.     }  
  533.   
  534.     /** 
  535.      * 最短读阻塞时间 
  536.      *  
  537.      * @return 
  538.      */  
  539.     public int getMiniReadIntervalMillSec() {  
  540.         return miniReadIntervalMillSec;  
  541.     }  
  542.   
  543.     public void setMiniReadIntervalMillSec(int miniReadIntervalMillSec) {  
  544.         this.miniReadIntervalMillSec = miniReadIntervalMillSec;  
  545.     }  
  546.   
  547.     /** 
  548.      * 连接超时时间 
  549.      *  
  550.      * @return 
  551.      */  
  552.     public int getConnectTimeout() {  
  553.         return connectTimeout;  
  554.     }  
  555.   
  556.     public void setConnectTimeout(int connectTimeout) {  
  557.         this.connectTimeout = connectTimeout;  
  558.     }  
  559.   
  560.     /** 
  561.      * 最大读阻塞时间 
  562.      *  
  563.      * @return 
  564.      */  
  565.     public int getMaxReadTimeout() {  
  566.         return maxReadTimeout;  
  567.     }  
  568.   
  569.     public void setMaxReadTimeout(int maxReadTimeout) {  
  570.         this.maxReadTimeout = maxReadTimeout;  
  571.     }  
  572.   
  573. }

http://blog.csdn.net/chaofanwei/article/details/14130179

http://www.iteye.com/topic/284636

原文地址:https://www.cnblogs.com/softidea/p/4553665.html