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

12 篇文章 0 订阅

          最近在做一个远程控制的模块,其中用到了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;// 数据字节255
	private 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~127
			if (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;
	}

}


 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值