题目3 子网划分工具的设计与实现 (以软件形式验收,要求能够讲授相应的子网划分的原理及过程,基本要求是定长子网划分,若能考虑实现可变长子网划分,作为成绩提升的一个考量)
1、设计要求
(1)编程实现一个子网划分的简单工具。
(2)能够根据用户输入的网络地址和子网掩码,判断出用户输入的合法性及网络的类别(A、B、C地址)。
(3)能够计算出下列参数:子网数及有效子网、每个子网的主机数、每个子网IP范围及广播地址。
(4)应有相应的帮助提示及良好的结果输出组织,易于用户使用和查看结果。
子网划分原理
有很多博客已经讲的非常好了,请各位自行百度(❁´◡`❁)
代码实现
下面给出C++实现供需要的小伙伴参考。写的时候时间紧,代码有些凌乱,大家多多包涵,欢迎大佬指正
#include <iostream>
#include <string>
#include <sstream>
#include <math.h>
#include <string.h>
#include <bitset>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;
class dotDec{
public:
dotDec(){}
~dotDec(){}
/**
* 用点分10进制数组来更新它对应的二进制数
*/
void update_dtob(){
bin=0;
for (int i=0;i<4;++i){
bin |= (dec[i] & _mask);
if (i==3) break;
bin <<= 8;
}
}
/**
* 用二进制数更新它对应的点分10进制数组
*/
void update_btod(){
memset(dec,0,sizeof(dec));
unsigned int tmp = bin;
for (int i=3;i>=0;--i){
dec[i] |= (tmp & _mask);
tmp >>= 8;
}
}
/**
* 返回一个点分10进制的字符串
* 注意:调用前及时更新10进制数组
*/
string toString(){
stringstream ss;
ss<<dec[0]<<"."<<dec[1]<<"."<<dec[2]<<"."<<dec[3];
return ss.str();
}
int _mask = (1<<8) -1;
int dec[4];
unsigned int bin;
};
class subnetPartitioning{
public:
subnetPartitioning(){}
~subnetPartitioning(){}
/**
* 检查输入数据的格式,并将输入的点分10进制字符串转换成整数数组
*/
void extractVals(const string &str,dotDec* data){
int startPos=0, j=0;
for (int i=0;i<str.size(),j<4;++i){
if ((str[i]<'0' || str[i]>'9') && str[i]!='.') throw "输入格式错误";
if (str[i]=='.' || i==str.size()-1){
data->dec[j] = stoi(str.substr(startPos,i-startPos+1));
if (data->dec[j] > 255) throw "输入格式错误";
startPos = i+1;
++j;
}
}
if (j!=4) throw "输入格式错误";
data->update_dtob();
}
/**
* 求一个整数的二进制的前bit位中有多少个1
* @param n 整数
* @param bit 前bit位
*/
int numof_1(unsigned int n, int bit){
int num=0;
for (int i=0;i<bit;++i){
if (n>>i & 1) ++num;
}
return num;
}
/**
* 检查掩码是否合法
*/
void checkMask(){
if ((mask.dec[3]!=0 && (mask.dec[2]!=255 && mask.dec[1]!=255 && mask.dec[0]!=255)) ||
(mask.dec[2]!=0 && mask.dec[2]!=255 && (mask.dec[1]!=255 && mask.dec[0]!=255 && mask.dec[3]!=0)) ||
(mask.dec[1]!=0 && mask.dec[1]!=255 && (mask.dec[0]!=255 && mask.dec[1]!=0 && mask.dec[2]!=0))
) throw "掩码格式错误";
}
/**
* 检查ip类型
*/
void checkIP(){
if (ip.dec[0] > 0 && ip.dec[0] <= 126) {
netType='A';
cout<<"本IP类型为A类"<<endl;
} else if (ip.dec[0] >= 128 && ip.dec[0] <= 191) {
netType='B';
cout<<"本IP类型为B类"<<endl;
} else if (ip.dec[0] >= 192 && ip.dec[0] <= 223) {
netType='C';
cout<<"本IP类型为C类"<<endl;
} else {
throw "无效的IP地址类别";
}
}
/**
* 静态子网划分,因为题目没有提到在这一步需要输入要划分的子网数
* 所以这个实际上是通过主机ip和子网掩码来推断原始的网络地址和可以划分的子网数
*/
void subnets(){
int borrowedHosts = 0; //借用的主机位
int networkBit = numof_1(mask.bin,32); //网络位
int nowPos = -1; //当前借位的位置(32位分成4段,这个表示发生借位的那一段)
networkAddress.bin = (ip.bin & mask.bin); //计算网络地址
networkAddress.update_btod();
for (int i=0;i<4;++i){
if (mask.dec[i]==255) continue;
nowPos = i;
break;
}
if (netType=='A'){
borrowedHosts = networkBit - 8;
} else if (netType=='B') {
borrowedHosts = networkBit - 16;
}else if (netType=='C'){
borrowedHosts = networkBit - 24;
}
int hostBit = 32 - networkBit; //主机位
int numOfsubnets = pow(2,borrowedHosts); //子网数
int numOfAvailableHosts = pow(2,hostBit) - 2; //每子网可用主机数
cout<<"子网数:"<<numOfsubnets<<endl;
cout<<"每子网可用主机数:"<<numOfAvailableHosts<<endl;
int stepSize = 256 - mask.dec[nowPos]; //子网增量
cout<<"有效子网:"<<stepSize-2<<endl<<endl;
// 淦! (╯°□°)╯︵ ┻━┻
// 或许应该把IP及其二进制数作为一个整体封装一下
dotDec start=networkAddress, end=networkAddress;
end.bin |= (((1<<borrowedHosts) -1)<<hostBit);
while(start.bin<=end.bin){
dotDec s_ip = start ,e_ip = start;
s_ip.bin &= ~((1<<hostBit)-1); //主机位全设为0
e_ip.bin |= ((1<<hostBit)-1); //主机位全设为1
s_ip.update_btod();
e_ip.update_btod();
cout<<"网络号:"<<s_ip.toString()<<endl;
cout<<"广播地址:"<<e_ip.toString()<<endl;
cout<<"IP范围:"<<s_ip.toString()<<"~"<<e_ip.toString()<<endl;
//下面计算可用ip
s_ip.bin += 1;
e_ip.bin -= 1;
s_ip.update_btod();
e_ip.update_btod();
cout<<"可用IP范围:"<<s_ip.toString()<<"~"<<e_ip.toString()<<endl<<endl;
start.bin += (1<<hostBit);
}
}
/**
* 寻找最少需要几位主机位才能表示当前的主机数
* @param host 主机数
* @return 需要的主机位数
*/
int findMinLenHostBit(int host){
for (int i=0;i<32;++i){
if ((1<<i)-2 >= host) return i;
}
throw "主机位不够!";
return -1;
}
/**
* 动态子网划分
* @param hostNum 包含若干pair<int,int>的vector,pair.first为序号,pair.second为主机数
*/
void vlsm_subnets(vector<pair<int,int>> hostNum){
sort(hostNum.begin(),hostNum.end(),[](pair<int,int>& a, pair<int,int>& b)->bool {return a.second>b.second;});
// 先排序,从最大主机数开始划分
int networkBit = numof_1(mask.bin,32); //网络位
networkAddress.bin = ip.bin & mask.bin; //网络地址
networkAddress.update_btod();
for (int i=0;i<hostNum.size();++i){
int hostBit = findMinLenHostBit(hostNum[i].second);
int borrowedHostBit = 32 - hostBit - networkBit; //可借用的主机位,用来表示子网
if (borrowedHostBit<=0) throw "可借用的主机位不足";
dotDec s_ip = networkAddress ,e_ip = networkAddress, newMask;
s_ip.bin &= ~((1<<hostBit)-1);
e_ip.bin |= ((1<<hostBit)-1);
s_ip.update_btod();
e_ip.update_btod();
cout<<"第"<<hostNum[i].first<<"个子网:"<<endl;
cout<<"网络号:"<<s_ip.toString()<<endl;
cout<<"广播地址:"<<e_ip.toString()<<endl;
cout<<"IP范围:"<<s_ip.toString()<<"~"<<e_ip.toString()<<endl;
//下面计算可用ip
s_ip.bin += 1;
e_ip.bin -= 1;
s_ip.update_btod();
e_ip.update_btod();
cout<<"可用IP范围:"<<s_ip.toString()<<"~"<<e_ip.toString()<<endl;
newMask.bin = ~0;
newMask.bin &= ~((1<<hostBit)-1);
newMask.update_btod();
cout<<"子网掩码:"<<newMask.toString()<<endl<<endl;
networkAddress.bin += (1<<hostBit);
}
}
bool input(){
string str;
try{
cout<<"请输入网络地址(格式如:x1.x2.x3.x4):"<<endl;
cin>>str;
extractVals(str,&ip);
cout<<"请输入子网掩码(格式为:m1.m2.m3.m4):"<<endl;
cin>>str;
extractVals(str,&mask);
checkMask();
checkIP();
}catch(const char* e){
cout<<e<<endl;
return false;
}
return true;
}
bool input2(){
string str;
int subnet,x;
vector<pair<int,int>> hostNum;
try{
cout<<"请输入网络地址(格式如:x1.x2.x3.x4):"<<endl;
cin>>str;
extractVals(str,&ip);
cout<<"请输入子网掩码(格式为:m1.m2.m3.m4):"<<endl;
cin>>str;
extractVals(str,&mask);
checkMask();
checkIP();
cout<<"请输入要划分的子网数:";
cin>>subnet;
if (subnet<=0) throw "输入有误";
for (int i=0 ;i<subnet;++i){
cout<<"输入第"<<i+1<<"个子网的主机数:";
cin>>x;
hostNum.push_back(make_pair(i,x));
}
vlsm_subnets(hostNum);
}catch(const char* e){
cout<<e<<endl;
return false;
}
return true;
}
private:
dotDec ip;
dotDec mask;
dotDec networkAddress;
char netType;
};
int main(){
subnetPartitioning test;
cout<<"请选择功能,1.静态子网划分,2.可变长子网划分,3.退出"<<endl;
int x;
while(cin>>x){
if(x==1){
while (!test.input());
test.subnets();
}else if(x==2){
while (!test.input2());
}else{
break;
}
cout<<"请选择功能,1.静态子网划分,2.可变长子网划分,3.退出"<<endl;
}
return 0;
}```