獲取同網段IP?
對網絡知識不牢靠的我,太小看了這東西,所以花費了我不少時間。
條件:
- 一個IP地址
- 一個子網掩碼
像這樣返回地址列表
[192.168.1.252, 192.168.1.253, 192.168.1.254, 192.168.1.255]
[192.168.1.252, 192.168.1.253, 192.168.1.255]
[192.168.1.253]
public static void main(String[] args) {
System.out.println(getLocalAreaIpList("192.168.1.254", "255.255.255.252"));
System.out.println(getLocalAreaIpList("192.168.1.254", "255.255.255.252", true));
System.out.println(getLocalAreaIpList("192.168.1.254", "255.255.255.252", true, true));
}
我經歷了些什麼:
- 格式判斷
- 轉換IP爲二進制數組
- 計算子網數,主機數
- 對二進制計算
- 二進制轉IP
- 返回
格式判斷
用到了一些東西, 如二進制轉換與運算,正則表達式
正則, 用於判斷IP和子網掩碼是否合法
/**
* 正則表達式: 匹配IPV4地址字符串
*/
private final static String IPV4 = "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
private final static String IP_MASK = "^((128|192)|2(24|4[08]|5[245]))(\\.(0|(128|192)|2((24)|(4[08])|(5[245])))){3}$";
/**
* 判斷字符串是否爲IPV4地址格式
*
* @param ip 要驗證的ip字符串
* @return 是 true/ 否 false
*/
public static boolean isIp(String ip) {
if (ip == null) return false;
Pattern patt = Pattern.compile(IPV4);
return patt.matcher(ip).matches();
}
/**
* 判斷字符串是否爲IPV4 子網掩碼格式
*
* @param mask 要驗證的子網掩碼字符串
* @return 是 true/ 否 false
*/
public static boolean isIpMask(String mask) {
if (mask == null) return false;
Pattern patt = Pattern.compile(IP_MASK);
return patt.matcher(mask).matches();
}
轉換IP爲二進制
這裏有兩個方法, 一個用於轉二進制字符串數組,另一個是數值型二進制數組
/**
* 獲取IP地址或掩碼二進制數組
* @param ip IP或子網掩碼
* @return 二進制數組如[11111111,11111111,11111111,11111111]
*/
public static String [] getIpBinary(String ip){
String[] strs = ip.split("\\.");
for (int i = 0; i < 4; i++){
strs[i] = Integer.toBinaryString(Integer.parseInt(strs[i]));
if(strs[i].length() < 8) {
StringBuilder zero = new StringBuilder();
for (int j = 0; j < 8 - strs[i].length(); j++) zero.append("0");
strs[i] = zero.toString() + strs[i];
}
}
return strs;
}
/**
* 將二進制字符串數組轉換爲byte數組,長度由第一個值的長度決定
* @param binaryStrArr 二進制數組
* @exception ArrayIndexOutOfBoundsException 如果數組二進制字符串長度不同,將會拋出異常
* @return 如[1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0]
*/
public static byte[] toBinary(String[] binaryStrArr){
int bl = binaryStrArr[0].length();
byte[] bytes = new byte[bl * binaryStrArr.length];
for(int i = 0; i < binaryStrArr.length; i++){
for (int j = 0; j < bl; j++) bytes[i * bl + j] = (byte) (binaryStrArr[i].charAt(j) == '1' ? 1 : 0);
}
return bytes;
}
計算子網數,主機數
由於是IPv4 總長32, 子網掩碼爲1的累加,加起來就是子網掩碼有效位;
主機位長度爲32-子網掩碼位數
最大主機數也即是 1 << 主機位數, 1位 0 ~ 1, 2位 0 ~ 3
byte[] maskArr = toBinary(maskBinary);//二進制掩碼數組
byte[] ipArr = toBinary(ipBinary);//二進制IP數組
int maskLen = 0;//子網掩碼長度
for (int i = 0; i < maskArr.length; i++) maskLen += maskArr[i];
// int maskNumberLen = maskLen % 8;//子網位數,若爲0 則8位全爲主機號
// System.out.println("子網號位數:" + maskNumberLen);
int hostNumberLen = 32 - maskLen;//主機IP位數
// System.out.println("主機號位數:" + hostNumberLen);
int maxHost = 1 << hostNumberLen;
對二進制計算
這方法是對二進制數組進行增加某個值,用於IP生成時增加
/**
* 對二進制數組增加指定值
* <p>如果增加的值超出此數組長度二進制最大表示值, 數組將重置爲0, 從0開始增加</p>
* @param binaryArray 二進制數組值應當全爲1或0
* @param plus 增加的數值10進制
*/
public static void binaryArrayPlus(byte[] binaryArray, int plus){
binaryArrayPlus(binaryArray, binaryArray.length - 1, plus);
}
/**
* 對二進制數組增加指定值
* <p>如果增加的值超出此數組長度二進制最大表示值, 數組將重置爲0, 從0開始增加</p>
* @param binaryArray 二進制數組值應當全爲1或0
* @param index 下標
* @param plus 增加的數值10進制
*/
private static void binaryArrayPlus(byte[] binaryArray, int index, int plus){
if(index < 0) {
binaryArray[0] = 0;
return;
}
binaryArray[index] = (byte) (binaryArray[index] + 1);
plus--;
//如果進位,則遞歸進位
if(binaryArray[index] > 1){
binaryArrayPlus(binaryArray, index - 1, 1);
binaryArray[index] = 0;
}
//如果增加的數超過1
if(plus > 0) binaryArrayPlus(binaryArray, index, plus);
}
二進制轉IP
再就是將二進制數組轉爲IP字符串, 數學不好算法可能略差。
StringBuilder genIp = new StringBuilder();//生成的IP
//轉換爲IP地址
int decimal = 0;
for(int j = 0; j < 32; j++){
decimal += mod[j] << (7 - j % 8);
if(j != 0 && (j+1) % 8 == 0){
if(genIp.length() == 0) genIp.append(decimal);
else genIp.append(".").append(decimal);
decimal = 0;
}
}
//genIp.toString();//轉換的IP
返回,調用核心方法
調用方法返回IP列表
/**
* 獲取局域網內的所有IP, 包含參數地址, 包含首尾地址
*
* @param ip 用作查找基礎的IP,返回此IP網段的地址列表
* @param mask 子網掩碼
* @return IP list 或 null, 如果地址非法則返回null
*/
public static List<String> getLocalAreaIpList(String ip, String mask){
return getLocalAreaIpList(ip, mask, false);
}
/**
* 獲取局域網內的所有IP, 包含首尾地址
*
* @param ip 用作查找基礎的IP,返回此IP網段的地址列表
* @param mask 子網掩碼
* @param containParamIp 返回結果是否包含傳入參數的IP
* @return IP list 或 null, 如果地址非法則返回null
*/
public static List<String> getLocalAreaIpList(String ip, String mask, boolean containParamIp ){
return getLocalAreaIpList(ip, mask, containParamIp, false);
}
/**
* 獲取局域網內的所有IP
*
* @param ip 用作查找基礎的IP,返回此IP網段的地址列表
* @param mask 子網掩碼
* @param containParamIp 返回結果是否包含傳入參數的IP
* @param ignoreFirstAndLastIp 是否忽略首尾IP,(網段地址與廣播地址)
* @return IP list 或 null, 如果地址非法則返回null
*/
public static List<String> getLocalAreaIpList(String ip, String mask, boolean containParamIp, boolean ignoreFirstAndLastIp) {
if (!isIp(ip) || !isIpMask(mask)) return null;//非法ip或子網掩碼
String[] maskBinary = getIpBinary(mask);//子網掩碼二進制數組
//[11000000, 10101000, 00000000, 11111110]
String[] ipBinary = getIpBinary(ip);//IP地址二進制數組
//取同網段部分
byte[] maskArr = toBinary(maskBinary);//二進制掩碼數組
byte[] ipArr = toBinary(ipBinary);//二進制IP數組
int maskLen = 0;//子網掩碼長度
for (int i = 0; i < maskArr.length; i++) maskLen += maskArr[i];
// int maskNumberLen = maskLen % 8;//子網位數,若爲0 則8位全爲主機號
// System.out.println("子網號位數:" + maskNumberLen);
int hostNumberLen = 32 - maskLen;//主機IP位數
// System.out.println("主機號位數:" + hostNumberLen);
int maxHost = 1 << hostNumberLen;
// System.out.println("支持主機個數:" + maxHost);
byte[] mod = new byte[32];//同網段二進制數組
for(int i = 0; i < 32; i ++) mod[i] = (byte)(maskArr[i] & ipArr[i]);
List<String> ipList = new ArrayList<>(maxHost);
StringBuilder genIp = new StringBuilder();//生成的IP
for(int i = 0; i < maxHost; i++){
//轉換爲IP地址
int decimal = 0;
for(int j = 0; j < 32; j++){
decimal += mod[j] << (7 - j % 8);
if(j != 0 && (j+1) % 8 == 0){
if(genIp.length() == 0) genIp.append(decimal);
else genIp.append(".").append(decimal);
decimal = 0;
}
}
binaryArrayPlus(mod, 1);//從0開始增加maxHost次
// System.out.println(genIp);//生成的IP
String generateIp = genIp.toString();
genIp.delete(0, genIp.length());//清空
if(ignoreFirstAndLastIp && (i == 0 || i == maxHost - 1)) continue;//跳過首位地址
if(containParamIp && generateIp.equals(ip)) continue;//跳過相同地址
ipList.add(generateIp);
}
return ipList;
}
個人對數學類的計算有一定遲鈍,研究很費時間,但偶爾做起來確實有點樂趣。以上。