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

时间:2023-03-09 19:43:55
关于telnet协议的研究以及用java进行封装实现自己的telnet客户端(转)

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

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

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

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

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