java程序中调用cmd,执行获取访问程序对应ip的mac信息,记录用户登录情况

业务场景为:记录用户使用系统情况,哪个帐号在什么时间通过哪个ip地址,哪个mac地址访问的系统。

双网卡的一定要看到最后

完整代码在后面。

一、启动 Windows 命令解释器的一个新实例执行命令

1.单命令

参数是命令行数组,例如:String [] cmd={  "cmd","/c","ping "+ip}

运行 cmd

/C      执行字符串指定的命令然后终止

执行 ping ip

Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。

Runtime.getRuntime().exec(cmd);创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。当没有 Process 对象的更多引用时,不是删掉子进程,而是继续异步执行子进程。

将命令执行输出的内容返回

/**
     * 执行cmd命令,返回执行结果
     * @param cmd 执行的命令
     * @return result 执行结果
     * @throws Exception
     */
    private static String callCmd(String [] cmd ) throws Exception{
        String result="";
        String line="";
        Process proc=Runtime.getRuntime().exec(cmd);
        InputStreamReader is= new InputStreamReader(proc.getInputStream());
        BufferedReader br=new BufferedReader(is);
        while((line=br.readLine())!=null){
            result += line;
        }
        return result;
    }

2.双命令

唯一不同的是多了一个判断

int i=proc.waitFor();//已经执行完第一个命令,准备执行第二个命令

//i代表执行失败的条数

如果i<=0则代表第一个命令执行成功。

          i>0则代表第一个命令执行失败

/**
	 * 执行cmd,another命令,返回another执行结果
	 * @param cmd 第一个命令
	 * @param another 第二个命令
	 * @return 第二个命令返回的执行结果
	 * @throws Exception
	 */
	private static String callCmd(String [] cmd ,String [] another) throws Exception{
		String result="";
		String line="";
		Runtime rt=Runtime.getRuntime();
		Process proc=rt.exec(cmd);
		int i=proc.waitFor();//已经执行完第一个命令,准备执行第二个命令
		if(i<=0){//i代表执行失败的条数
			//ping失败则不执行
			System.out.println("i = "+i);
			proc=rt.exec(another);
			InputStreamReader is= new InputStreamReader(proc.getInputStream());
			BufferedReader br=new BufferedReader(is);
			while((line=br.readLine())!=null){
				result += line;
			}
		}
		return result;
	}

二、根据ip处理命令行执行返回结果,找到匹配的Mac地址

返回结果示例:

C:\WINDOWS\system32>arp -a

接口: 101.51.227.192 --- 0x9
  Internet 地址         物理地址              类型
  101.51.227.144          90-fb-a6-f9-88-08     动态
  101.51.227.254          30-7b-ac-8b-24-52     动态
  101.51.227.255          ff-ff-ff-ff-ff-ff     静态
  224.0.0.22            01-00-5e-00-00-16     静态
  224.0.0.251           01-00-5e-00-00-fb     静态
  224.0.0.252           01-00-5e-00-00-fc     静态
  239.255.255.250       01-00-5e-7f-ff-fa     静态
  255.255.255.255       ff-ff-ff-ff-ff-ff     静态

接口: 192.168.43.143 --- 0xf
  Internet 地址         物理地址              类型
  192.168.43.1          1e-bf-b4-34-86-80     动态
  192.168.43.255        ff-ff-ff-ff-ff-ff     静态
  224.0.0.22            01-00-5e-00-00-16     静态
  224.0.0.251           01-00-5e-00-00-fb     静态
  224.0.0.252           01-00-5e-00-00-fc     静态
  239.255.255.250       01-00-5e-7f-ff-fa     静态
  255.255.255.255       ff-ff-ff-ff-ff-ff     静态

根据正则表达式过滤出返回内容中的所有mac地址。

将mac地址出现的下标与ip出现的下标进行比较,如果当前mac地址下标第一次大于ip下标则认为是 ip后面对应的mac地址。

就是我们所需要的mac地址。对比时因为网管的原因应排除(ff-ff-ff-ff-ff-ff)防止lastIndexOf对比时出现错误。

/**
	 * @param ip 目标ip
	 * @param sourceString  命令处理的结果字符串
	 * @param macSeparator  mac分割符号
	 * @return mac地址,用上面的分割符号表示
	 */
	private static String filterMacAddress(final String ip,final String sourceString,final String macSeparator){
		String result="";
		String regExp="((([0-9,A-F,a-f]{1,2}"+macSeparator+"){1,5})[0-9,A-F,a-f]{1,2})";
//		System.out.println("regExp="+regExp);
		Pattern pattern=Pattern.compile(regExp);
		Matcher matcher=pattern.matcher(sourceString);
		while(matcher.find()){
			result =matcher.group(1);//此处为符合正则表达式的字符串  也就是mac地址
//			System.out.println(sourceString.indexOf(ip));//此处为第一次出现ip匹配的下标
//			System.out.println(sourceString.lastIndexOf(matcher.group(1)));//最后一次出现这个mac地址的下标
//			System.out.println(matcher.group(1));//此次循环匹配的mac地址
//			if(sourceString.indexOf(ip)<=sourceString.lastIndexOf(matcher.group(1))){//单网卡
			if(sourceString.indexOf(ip)<=sourceString.lastIndexOf(matcher.group(1))&&!"ff-ff-ff-ff-ff-ff".equals(result)){//双网卡
				//如果出现ip的下标小于出现mac地址的下标,则此max地址认为是 ip后面 的mac地址
				break;//如果有多个ip,则只匹配本ip对应的Mac地址
			}
		}
		return result;
	}

三、根据不同系统,创建执行命令,

现执行ping ip,如果ping通则继续执行,

如果ping不通则不执行。

/**
	 * Windows系统下 根据ip获取mac地址
	 * @param ip 目标ip
	 * @return Mac Address
	 * @throws Exception
	 */
	private static String getMacInWindows(final String ip)throws Exception{
		String result="";
		String [] cmd ={   "cmd","/c","ping "+ip};
		String [] another={"cmd","/c","arp -a"};
		String cmdResult=callCmd(cmd,another);
		result=filterMacAddress(ip, cmdResult, "-");
		return result;
	}
	
	/**
	 * Linux系统下 根据ip获取mac地址
	 * @param ip 目标ip
	 * @return Mac Address
	 * @throws Exception
	 */
	private static String getMacInLinux (final String ip)throws Exception{
		String result="";
		String [] cmd ={"/bin/sh","-c","ping "+ip+" -c 2 && arp -a"};
		String cmdResult=callCmd(cmd);
		result=filterMacAddress(ip, cmdResult, ":");
		return result;
	}

四、写个调用方法,先调用windows获取方法,如果抛出异常,则有可能是linux系统。否则就是其他问题。

public static String getMacAddress(String ip){
		String macAddress="";
		try {
			macAddress=getMacInWindows(ip);
		} catch (Exception e) {
			try {//如果执行windows命令有异常,有可能是linux系统
				macAddress=getMacInLinux(ip);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		return macAddress;
	}

五、最后写个main方法测试

public static void main(String[] args) {
//		String ip="224.0.0.22";
		String ip="127.0.0.1";
		System.out.println(getMacAddress(ip));
	}

 

完整代码如下:

package test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tools.ant.types.CommandlineJava.SysProperties;

/**
 * 根据ip获取mac地址
 * @author songfelicity
 * 2020年9月14日 14:28:41
 */
public class GetMacAddress {
	
	/**
	 * 执行cmd命令,返回执行结果
	 * @param cmd
	 * @return
	 * @throws Exception
	 */
	private static String callCmd(String [] cmd ) throws Exception{
		String result="";
		String line="";
		Process proc=Runtime.getRuntime().exec(cmd);
		InputStreamReader is= new InputStreamReader(proc.getInputStream());
		BufferedReader br=new BufferedReader(is);
		while((line=br.readLine())!=null){
			result += line;
		}
		return result;
	}
	
	/**
	 * 执行cmd,another命令,返回another执行结果
	 * @param cmd 第一个命令
	 * @param another 第二个命令
	 * @return 第二个命令返回的执行结果
	 * @throws Exception
	 */
	private static String callCmd(String [] cmd ,String [] another) throws Exception{
		String result="";
		String line="";
		Runtime rt=Runtime.getRuntime();
		Process proc=rt.exec(cmd);
		int i=proc.waitFor();//已经执行完第一个命令,准备执行第二个命令
		if(i<=0){//i代表执行失败的条数
			//ping失败则不执行
			System.out.println("i = "+i);
			proc=rt.exec(another);
			InputStreamReader is= new InputStreamReader(proc.getInputStream());
			BufferedReader br=new BufferedReader(is);
			while((line=br.readLine())!=null){
				result += line;
			}
		}
		return result;
	}
	
	/**
	 * @param ip 目标ip
	 * @param sourceString  命令处理的结果字符串
	 * @param macSeparator  mac分割符号
	 * @return mac地址,用上面的分割符号表示
	 */
	private static String filterMacAddress(final String ip,final String sourceString,final String macSeparator){
		String result="";
		String regExp="((([0-9,A-F,a-f]{1,2}"+macSeparator+"){1,5})[0-9,A-F,a-f]{1,2})";
//		System.out.println("regExp="+regExp);
		Pattern pattern=Pattern.compile(regExp);
		Matcher matcher=pattern.matcher(sourceString);
		while(matcher.find()){
			result =matcher.group(1);//此处为符合正则表达式的字符串  也就是mac地址
//			System.out.println(sourceString.indexOf(ip));//此处为第一次出现ip匹配的下标
//			System.out.println(sourceString.lastIndexOf(matcher.group(1)));//最后一次出现这个mac地址的下标
//			System.out.println(matcher.group(1));//此次循环匹配的mac地址
//			if(sourceString.indexOf(ip)<=sourceString.lastIndexOf(matcher.group(1))){//单网卡
			if(sourceString.indexOf(ip)<=sourceString.lastIndexOf(matcher.group(1))&&!"ff-ff-ff-ff-ff-ff".equals(result)){//双网卡
				//如果出现ip的下标小于出现mac地址的下标,则此max地址认为是 ip后面 的mac地址
				break;//如果有多个ip,则只匹配本ip对应的Mac地址
			}
		}
		return result;
	}
	
	/**
	 * Windows系统下 根据ip获取mac地址
	 * @param ip 目标ip
	 * @return Mac Address
	 * @throws Exception
	 */
	private static String getMacInWindows(final String ip)throws Exception{
		String result="";
		String [] cmd ={   "cmd","/c","ping "+ip};
		String [] another={"cmd","/c","arp -a"};
		String cmdResult=callCmd(cmd,another);
		result=filterMacAddress(ip, cmdResult, "-");
		return result;
	}
	
	/**
	 * Linux系统下 根据ip获取mac地址
	 * @param ip 目标ip
	 * @return Mac Address
	 * @throws Exception
	 */
	private static String getMacInLinux (final String ip)throws Exception{
		String result="";
		String [] cmd ={"/bin/sh","-c","ping "+ip+" -c 2 && arp -a"};
		String cmdResult=callCmd(cmd);
		result=filterMacAddress(ip, cmdResult, ":");
		return result;
	}
	
	public static String getMacAddress(String ip){
		String macAddress="";
		try {
			macAddress=getMacInWindows(ip);
		} catch (Exception e) {
			try {//如果执行windows命令有异常,有可能是linux系统
				macAddress=getMacInLinux(ip);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		return macAddress;
	}
	
	
	public static void main(String[] args) {
		String ip="224.0.0.22";
		System.out.println(getMacAddress(ip));
	}
}

 

测试过程中发现一个bug,因为是通过返回的结果通过indexOf+lastIndexOf进行匹配的。

当我测试的ip写成 1092.168.43.1时

图中涉及两处通过ip匹配都符合,所以此时获取的mac地址是 :ff-ff-ff-ff-ff-ff

当使用ff-ff-ff-ff-ff-ff最后一次下标是 获得的是最后一次出现此mac地址的下标。

此时这个下标是大于ip出现的下标,所以返回的mac地址为ff-ff-ff-ff-ff-ff。

分析:可能是因为我使用双网卡的关系。需要注意一下。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

songfelicity

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值