[Java]一个WiFi管理器(获取WiFi连接的网关的ip和信息)和热点管理器(获取连接本机的热点的设备的ip、MAC和信息)

注:笔者未学习过计算机网络相关的知识,只是在做socket通信项目时接触到这块知识,对一些名词概念使用不当请多多包涵,本篇文章的目的为提供一个笔者原创的Java网络信息获取工具类,并在一定程度上对这个领域的小白指北。

应用场景

笔者在做一个电脑<-->手机之间进行局域网数据传输的项目,这时就需要调用Java中的socket类,而socket的初始化需要用到对方的ip和端口(当对方为服务端时)。换言之,对于电脑来说,在“电脑开热点手机连接”和“手机开热点电脑连接”两种情况下,我都需要知道手机的ip地址。

在手机端,Android提供了封装好的一个WiFiManager类,通过它能很容易的获取自己和对方的WiFi信息,而通过对“/proc/net/arp”的读取可以得到热点信息,在网上很容易能找到关于它们的代码。

在电脑端,我们可以在Windows的UI界面中看到WiFi的名称和连接热点的设备的名称和ip地址(在“设置->网络和Internet->移动热点”中),但是无法获取WiFi的网关(路由器)的地址。更大的问题是,Java不提供任何像Android中WiFiManager类那样的类,至少我在网上没查到。

Java这条路就算断了,唯一的方向就只有Windows中无敌却又难用的cmd了。笔者通过大量的搜索资料和尝试命令,终于把需要的信息通过cmd获取到了。

 

为了方便理解,下面的本机(my)指的都是电脑,本机的ip地址称为myIP,与本机进行连接的设备(如手机)称为连接者(connecter),其ip地址称为connecterIP

相关的cmd命令:

一.WiFi部分

1.获取本机ip:在cmd中使用“ipconfig”命令,“无线局域网适配器 WLAN:”下的“IPv4 地址 . . . . . . . . . . . . :”栏即为本机ip

2.获取连接的WiFi名称:使用“netsh wlan show interfaces”命令,“SSID”栏即为WiFi名称。

3.获取连接者ip:使用“ARP -a”命令,找到“接口:”后的ip地址为本机ip的部分,下面与本机ip属于同一网段且物理地址不为“ff-ff-ff-ff-ff-ff”的即为连接者ip

二.热点部分

1.获取本机ip:在cmd中使用“ipconfig”命令,“无线局域网适配器 本地连接”下的“IPv4 地址 . . . . . . . . . . . . :”栏即为本机ip

2.获取连接者ip:使用“ARP -a”命令,找到“接口:”后的ip地址为本机ip的部分,下面与本机ip属于同一网段且物理地址不为“ff-ff-ff-ff-ff-ff”的即为连接者ip

3.获取连接者的名称:使用“tracert connecterIP”命令(connecterIP为第二步获得的连接者ip),即可跟踪到连接者的名称。(则与Windows UI界面上显示的名称稍有不同(但不影响对设备的识别),但是笔者还没找到获取UI界面上内容的方法)

 

笔者在Java中获取cmd输出的信息,使用正则表达式提取出其中的信息,并存储在类的属性中,实现了WiFiManager(WiFi管理器)和HotspotManager(热点管理器)两个工具类。

 

代码:

1.Cmd类(获取cmd输出的信息)

(修改自https://blog.csdn.net/w405722907/article/details/78610503,在此对该文章作者表示感谢,之前笔者使用的另一个代码有错,读取内容混乱导致笔者浪费了很多时间)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Cmd {
	public static String command(String cmd){//获取cmd输出
		try {
			Process process = Runtime.getRuntime().exec(cmd);
			
			//关闭流释放资源
	    	if(process != null){
	    		process.getOutputStream().close();
	    	}
	    	InputStream in = process.getInputStream();
	    	BufferedReader br = new BufferedReader(new InputStreamReader(in));
	    	
	    	StringBuilder result = new StringBuilder();
	    	String tmp = null;
	    	while ((tmp = br.readLine()) != null) {
	    		result.append(tmp+"\r\n");//将tmp内容附加(append)到StringBuilder类中
	    	}
	    	return result.toString();
	    	
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
			return null;
		}
	}
}

2.WiFiManager类(需要调用Cmd类的command方法)

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 一个WiFi管理类,用于获取WiFi的信息,用于通信
 * @see #isWiFiConnected()
 * @see #getMyIP()
 * @see #getConnecterIP()
 * @see #getConnecterMAC()
 * @see #isConnecterHDCP()
 * 
 * @author blademaster
 *
 */
public class WiFiManager {
	private boolean isWiFiConnected=false;
	private String myIP=null;//本机的WiFi ip
	private String connecterIP=null;//本机连接的路由的IP
	private String connecterMAC=null;//本机连接的路由的MAC
	private boolean isConnecterHDCP=false;//本机连接的路由是否为HDCP动态
	
	public WiFiManager() {
		// TODO 自动生成的构造函数存根
		
		//******************由"ipconfig"获取myIP*********************
		String str=Cmd.command("ipconfig");
		str=str+"\r\n";//增加用于确定文字分段的回车

		//获取“无线局域网适配器 WLAN”段
		String WLAN_str=null;
		Pattern pattern = Pattern.compile("无线局域网适配器 WLAN:\r\n\r\n[\\s\\S]*?\r\n\r\n");//设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
		Matcher matcher = pattern.matcher(str);//对str进行正则表达式搜索
		if(matcher.find()){
			int start = matcher.start();
		    int end = matcher.end();
		    WLAN_str=str.substring(start,end);
		}
		if(WLAN_str==null) {
			return;
		}
		
		//获取myIP
		pattern = Pattern.compile("IPv4 地址 . . . . . . . . . . . . : ");//设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
		matcher = pattern.matcher(WLAN_str);//对str进行正则表达式搜索
		if(matcher.find()){
		    int end = matcher.end();
		    myIP=WLAN_str.substring(end).split("\r\n")[0];//首先截取匹配到的字符串,然后读到回车,获取ip地址
		    isWiFiConnected=true;
		}
		else {
			isWiFiConnected=false;
			return;
		}
		
		//当WiFi连接时
		//******************由"ARP -a"获取connecterIP*********************
		str=Cmd.command("ARP -a");
		str=str+"\r\n";//增加用于确定文字分段的回车

		//获取connecterIP
		pattern = Pattern.compile("接口: "+myIP+"[\\s\\S]*?类型\r\n");//设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
		matcher = pattern.matcher(str);//对str进行正则表达式搜索
		if(matcher.find()){
		    int end = matcher.end();
		    String connecter_str=str.substring(end).split("\r\n")[0];//首先截取匹配到的字符串,然后读到回车,获取ip地址
		    connecterIP=connecter_str.split("\\s+")[1];//"\\s+"为多个空格的正则表达式
		    connecterMAC=connecter_str.split("\\s+")[2];
		   	isConnecterHDCP=connecter_str.split("\\s+")[3].equals("动态") ? true : false;
		}
	}
	
	/**
	 * 判断WiFi是否连接
	 * @return
	 */
	public boolean isWiFiConnected() {
        return isWiFiConnected;
    }
	
	/**
	 * 返回本机的WLAN ip
	 * @return
	 */
    public String getMyIP() {
        return myIP;
    }

    /**
   	 * 返回本机连接的设备的ip
   	 * @return
   	 */
    public String getConnecterIP() {
        return connecterIP;
    }

    /**
   	 * 返回本机连接的设备的MAC
   	 * @return
   	 */
    public String getConnecterMAC() {
        return connecterMAC;
    }

    /**
   	 * 返回本机连接的设备的状态(静态or动态)
   	 * @return
   	 */
    public boolean isConnecterHDCP() {
        return isConnecterHDCP;
    }
    
    /**
     * 获取正在连接的WiFi的名称(SSID)
     * @return
     */
    public static String getConnectingWiFiSSID() {
    	String str=Cmd.command("netsh wlan show interfaces");
    	Pattern pattern = Pattern.compile("SSID[\\s\\S]*?: ");//设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
		Matcher matcher = pattern.matcher(str);//对str进行正则表达式搜索
		if(matcher.find()){
		    int end = matcher.end();
		    String SSID=str.substring(end).split("\r\n")[0];//首先截取匹配到的字符串,然后读到回车,获取ip地址
		    return SSID;
		}
		return null;
    }
}

3.HotspotManager类(需要调用Cmd类的command方法)

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 一个热点管理类,用于获取热点的信息,用于通信
 * @see #isHotspotConnected()
 * @see #getMyIP()
 * @see #getConnecterIP()
 * @see #getConnecterMAC()
 * @see #isConnecterHDCP()
 * 
 * @author blademaster
 *
 */
public class HotspotManager {
	private boolean isHotspotConnected=false;
	private ArrayList localIP=new ArrayList<>();//所有本地连接的地址
	private ArrayList myIP=new ArrayList<>();//本机的ip,与connecterIP对应
	private ArrayList connecterName=new ArrayList<>();//解析的主机名称
	private ArrayList connecterIP=new ArrayList<>();//连接本机的设备的IP
	private ArrayList connecterMAC=new ArrayList<>();//连接本机的设备的MAC
	private ArrayList isConnecterHDCP=new ArrayList<>();//连接本机的设备是否为HDCP动态,boolean为数据类型,不属于对象,不能作为ArrayList的类型
	
	public HotspotManager() {
		// TODO 自动生成的构造函数存根
		
		//******************由"ipconfig"获取myIP*********************
		String str=Cmd.command("ipconfig");
		str=str+"\r\n";//增加用于确定文字分段的回车

		//获取“无线局域网适配器 本地连接”段,由于可能存在多个本地连接,查找所有可能的本地连接
		ArrayList Local_str=new ArrayList<>();
		Pattern pattern = Pattern.compile("无线局域网适配器 本地连接[\\s\\S]*?\r\n\r\n[\\s\\S]*?\r\n\r\n");//设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
		Matcher matcher = pattern.matcher(str);//对str进行正则表达式搜索
		while(matcher.find()){
			int start = matcher.start();
		    int end = matcher.end();
		    Local_str.add(str.substring(start,end));
		}
		
		// 获取myIP
		for (int i = 0; i < Local_str.size(); i++) {
			pattern = Pattern.compile("IPv4 地址 . . . . . . . . . . . . : ");// 设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
			matcher = pattern.matcher(Local_str.get(i));// 对str进行正则表达式搜索
			if (matcher.find()) {
				int end = matcher.end();
				localIP.add(Local_str.get(i).substring(end).split("\r\n")[0]);// 首先截取匹配到的字符串,然后读到回车,获取ip地址
			} 
		}
		if(localIP.isEmpty()) {
			isHotspotConnected = false;
			return;
		}
		//当热点连接时
		//******************由"ARP -a"获取connecterIP*********************
		str=Cmd.command("ARP -a");
        str=str+"\r\n";//增加用于确定文字分段的回车

		for (int i = 0; i < localIP.size(); i++) {
			// 获取connecterIP
			pattern = Pattern.compile("接口: " + localIP.get(i) + "[\\s\\S]*?类型\r\n");// 设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
			matcher = pattern.matcher(str);// 对str进行正则表达式搜索
			if (matcher.find()) {
				int start = matcher.end();
				pattern = Pattern.compile("接口: " + localIP.get(i) + "[\\s\\S]*?类型\r\n[\\s\\S]*?\r\n\r\n");// 设置正则表达形式,[\\s\\S]*?为任意数量字符非贪婪正则表达式
				matcher = pattern.matcher(str);// 对str进行正则表达式搜索
				if (matcher.find()) {//注意要先matcher.find()才能调用matcher.end()
					int end = matcher.end()-4;// 除去两个回车(一个"\r\n"两个)
					String connecter_str = str.substring(start, end);// 首先截取匹配到的字符串,然后读到回车,获取ip地址
					
					String[] connecter_tag=connecter_str.split("\r\n");
					int n=0;
					while(!connecter_tag[n].split("\\s+")[2].equals("ff-ff-ff-ff-ff-ff")) {//应该添加局域网的判断,此处省略
						myIP.add(localIP.get(i));
						connecterIP.add(connecter_tag[n].split("\\s+")[1]);// "\\s+"为多个空格的正则表达式
						connecterMAC.add(connecter_tag[n].split("\\s+")[2]);
						isConnecterHDCP.add(connecter_tag[n].split("\\s+")[3].equals("动态") ? true : false);
						
						isHotspotConnected = true;//找到至少一个真实的连接者
						n++;
					}
				}
			}
		}
		for(int i=0;i getMyIP() {
        return myIP;
    }
    
    /**
	 * 返回连接本机热点的设备的ip(可能有多个)
	 * @return
	 */
    public ArrayList getConnecterIP() {
        return connecterIP;
    }

    /**
	 * 返回连接本机热点的设备的MAC(可能有多个)
	 * @return
	 */
    public ArrayList getConnecterMAC() {
        return connecterMAC;
    }

    /**
	 * 返回连接本机热点的设备的状态(静态or动态)(可能有多个)
	 * @return
	 */
    public ArrayList isConnecterHDCP() {
        return isConnecterHDCP;
    }
    
    /**
	 * 返回连接本机热点的设备的主机名称(可能有多个)
	 * @return
	 */
    public ArrayList getConnecterName() {
        return connecterName;
    }
    
    /**
     * 将热点连接设备的ip通过tracert命令解析为主机名
     * @param ip
     * @return
     */
    
    public static String IP2Hostname(String ip) {
		String str=Cmd.command("tracert "+ip);
		if(str.split("\\s+").length < 17) {//当未跟踪到主机名时
			return null;
		}
		String hostname=str.split("\\s+")[15];//通过对cmd输出分析得到
		hostname=hostname.split("\\.")[0];//去除.mshome.net后缀
		
		return hostname;
	}
}

 

使用方法:

1.WiFiManager类

通过“WiFiManager wiFiManager=new WiFiManager();”即可创建已获得WiFi信息的对象,然后调用其方法即可获取信息。

由于一般电脑只能连接一个WiFi,所以其对应的信息一般只有一个,返回的信息为String对象

2.HotspotManager类

通过“HotspotManager hotspotManager=new HotspotManager();”即可创建已获得热点信息的对象,然后调用其方法即可获取信息。

由于一台电脑的热点至多可供8台设备连接,所以connecterIP等信息可能不为一个,笔者返回的是ArrayList类的数据,这样便于管理和使用(不懂ArrayList类的同学可以查一下,使用起来非常简单)。

你可能感兴趣的:(Java)