第三次:程序优化及命令行操作

这个作业属于哪个课程 <班级的链接>
这个作业要求在哪里 <作业要求的链接>
这个作业的目标 程序优化及命令行操作
作业正文 如下
其他参考文献 csdn yyds!

第二次作业中,我的程序明明是O(nm),但运行时间在40秒左右,实在太慢啦!以及仍未能实现作业要求的命令行操作(后继将学习相关算法继续优化)

于是开始慢慢摸索请教问题并改进,最终矛头指向了freopen和main函数的参数,详情如下

关于main参数

  • main的实际编写为int main(int argc, char** argv){...},其中argc为main函数从控制台(也可以理解成命令行)读入的参数个数(可以理解成文件个数),而argv则为指向各个参数的char型数组指针,可以理解成argv[i]所存储的即为各个参数的文件名

  • 且使用该种方法多次freopen文件不需要使用cin.clear();

  • 于是则可以在代码中利用freopen多次打开不同packet文件,freopen的第一个参数为文件名字符串数组,打开不同packet文件时用argv[]作为参数传入freopen即可,相关代码如下:

    int file=grgc;
    for(file=2;file<argc;file++){
    	FILE *p=freopen(argv[file],"r",stdin);
        ...;
    }
    
  • 相关命令行命令如下:

程序设计思路框架

  1. 打开packet1.txt,读入一条数据;

  2. 打开rule1.txt,匹配规则集,直到规则匹配成功或遍历整个规则集;

  3. 重复上述步骤1和2遍历整个数据包;

  4. 接着打开packet2.txt,重复步骤1.2.3。

关键代码匹配IP地址的方法

  1. 将数据包和规则集的ip转化为二进制表示;
  2. 比较两者的二进制表示前n位是否相同(n为规则IP地址的网络前缀)

可能存在的问题

  1. 使用循环对二进制数比较的效率低于两个十进制数的直接比较;
  2. 多次重复使用freopen可能降低程序效率

优化方案

方案一:根据规则IP的网络前缀及CIDR划分法算出地址块的最小和最大地址,并将其转换成十进制数直接与数据包的IP进行比较匹配;
方案二:利用结构体对规则集读入一次并进行存储,减少freopen的使用次数。

优化结果及分析

方案一:程序运行效率没有明显提高;分析:求解最大最小地址时,仍需要用循环将其网络前缀位数之后的数转换成0/1,与原方案相比,在复杂度上只是乘以的常数小了一点,区别并不大
方案二:程序运行效率明显提高,从40s-50s优化至9.6s;分析:优化后减少了n次的freopen调用次数(n为数据量),极大地提高了程序运行效率

几个问题

  • 若使用string类似乎不能作为参数直接传入函数,只能通过传入其地址进行调用
  • 写class的时候注意:
    • 构造函数和析构函数声明的时候要加上一对大括号,其他函数不用
    • 使用命令行编译时,要连同类所在的.cpp文件一起编译
    • 上述两项若操作错误均会提示undifined reference to `某函数
  • 但是由于不太熟悉class操作以及认为struct就足够,所以我写完规则的类后最终还是选择使用struct

最终方案及其完整代码

结合方案一和方案二优化程序,完整代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
char ex='0'; //用于补全不够位数的二进制数
string ip_rule="";//用于存储转换二进制后的规则IP网络前缀
void ip_chansform(int a);//转换规则IP,返回前缀长度
// void chansform(int c,char *a); //函数1:IP地址十进制表示转换成点分十进制表示(参数1:IP十进制 , 参数2:存储转换后的点分十进制IP地址的字符数组地址)
int ip_check(ll a, int b,int c); //函数2:检测IP地址是否匹配,并以0/1作为返回值表示否/是;
int port_check(int p, int b, int c); //函数3:检测端口是否匹配,并以0/1作为返回值表示否/是;
int tcp_check(int t, int b); //函数4:检测传输协议是否匹配,并以0/1作为返回值表示否/是;
int stot(char *p,float length);//十六进制转换十进制
ll my_strtol(string *a);//二进制转十进制

struct rule{
    char rule_tcp[10];
    int rule_ip1[10],rule_ip2[10];
    int port_1_l,port_1_r,port_2_l,port_2_r;
};

rule r[1000];

int main(int argc, char** argv){
   clock_t start,finish;
    start=clock();
    fpos_t pos_1=0,pos_2=0;
    char waste;
    freopen("out.txt","w",stdout);
    int file,i,j,k;
    int check_1,check_2,check_3,check_4,check_5,port_1,port_2,tcp;
    ll ip_1,ip_2;
//    cin.clear();
    freopen(argv[1],"r",stdin);//读入规则集存储于struct rule中
    for(i=0;i<918;i++){
        for(j=0;j<5;j++){
            cin>>waste>>r[i].rule_ip1[j];
    //        cout<<r[i].rule_ip1[j]<<" ";
        }
        cin>>r[i].rule_ip2[0];
        for(j=1;j<5;j++){
            cin>>waste>>r[i].rule_ip2[j];
    //        cout<<r[i].rule_ip2[j]<<" ";
        }
        cin>>r[i].port_1_l>>waste>>r[i].port_1_r>>r[i].port_2_l>>waste>>r[i].port_2_r>>waste;
        cin>>waste>>r[i].rule_tcp;
    //    cout<<r[i].port_1_l<<" "<<r[i].port_1_r<<" "<<r[i].port_2_l<<" "<<r[i].port_2_r<<" "<<r[i].rule_tcp<<endl;
    }
    for(file=2;file<argc;file++){
        FILE *p=freopen(argv[file],"r",stdin);
        while(cin>>ip_1,cin>>ip_2,cin>>port_1,cin>>port_2,cin>>tcp){
            int cnt=0;
        //    fgetpos(p,&pos_1);    
            while(cnt<918){
                check_1=ip_check(ip_1,cnt,1);
                check_2=ip_check(ip_2,cnt,2);
                check_3=port_check(port_1,cnt,1);
                check_4=port_check(port_2,cnt,2);
                check_5=tcp_check(tcp,cnt);
                if(check_1&&check_2&&check_3&&check_4&&check_5) break; 
                else{
                    cnt++;
                }
                check_1=check_2=check_3=check_4=check_5=0;
            }
            if(cnt==918) cout<<"-1"<<endl;
            else cout<<cnt<<endl;
        //    cin.clear();
        //    freopen(argv[file],"r",stdin);
        //    fsetpos(p,&pos_1);
        }
        finish=clock();
        cout<<"程序执行时间为:"<<(double)(finish-start)/CLOCKS_PER_SEC<<endl;
       
    }
    return 0;
} 

void ip_chansform(int a){//只读一条规则
    char s[10];
    int i,j;
    ltoa(a,s,2);
    if(strlen(s)<8){
        for(j=0;j<8-strlen(s);j++){
            ip_rule+=ex;
        }
    }
    ip_rule+=s;
    return ;
}

int ip_check(ll a, int b, int c){
    ip_rule="";
    ll t,min,max,i;
    if(c==1){
        for(i=0;i<4;i++){
            ip_chansform(r[b].rule_ip1[i]);
        }
        t=r[b].rule_ip1[4];
    }else{
        for(i=0;i<4;i++){
            ip_chansform(r[b].rule_ip2[i]);
        }
        t=r[b].rule_ip2[4];
    }
    string ip_min=ip_rule,ip_max=ip_rule;
    for(i=t;i<ip_rule.length();i++){
        ip_min[i]='0';
        ip_max[i]='1';
    }
    min=my_strtol(&ip_min);
    max=my_strtol(&ip_max);
    if(a>=min&&a<=max){
        return 1;
    }else return 0;
}

int port_check(int p, int b, int c){
    if(c==1){
        if(p>=r[b].port_1_l&&p<=r[b].port_1_r) return 1;
        else return 0;
    }else{
        if(p>=r[b].port_2_l&&p<=r[b].port_2_r) return 1;
        else return 0;
    }
    
}

int tcp_check(int t, int b){
    char *p=r[b].rule_tcp;
    int i,x;
    if(r[b].rule_tcp[5]=='0'&&r[b].rule_tcp[6]=='0') return 1;
    x=stot(p,2);
    if(t==x) return 1;
    else return 0;
}

int stot(char *p,float length){
    int sum=0,i,t=length;
    for(i=0;i<t;i++){
        if(p[i]>='0'&&p[i]<='9'){
            sum+=(p[i]-'0')*pow(16,--length);
        }else if(p[i]>='A'&&p[i]<='F'){
            sum+=(p[i]-'A'+10)*pow(16,--length);
        }
    }
    return sum;
}

ll my_strtol(string *a){
    ll sum=0;
    float i;
    for(i=((*a).length()-1);i>=0;i--){
        if((*a)[i]=='1')
        sum+=pow(2,31-i);
    }
    return sum;
}

学习相关算法继续优化...

posted @ 2022-02-08 15:49  黄锴  阅读(34)  评论(0编辑  收藏  举报