第二次寒假作业

这个作业属于哪个课程 <班级的链接>
这个作业要求在哪里 <作业要求的链接>
这个作业的目标 模拟路由数据处理
作业正文 如下
其他参考文献 csdn yyds!

写在前面

因为在学习过程中注重理解知识和改进程序,对学习过程的记录较少

自学摸索来完成作业的感觉,这么说吧!人已经快疯掉了,但是也蛮有成就感,即使我的暴力解法需要三十几秒的运行时间,我再改进改进吧。

从最开始的一脸懵,开始慢慢学着配置vscode,编译运行、debug,而且没有开汉化包,以为能提升英语能力,但似乎没有啥效果哈哈哈,然后学着操作git,学习计算机网络五元组数据的知识,要搞明白他们是啥,还得搞明白他们之间应该如何相互转换、如何匹配,还有c++的一些知识,但是感觉如果把类、对象、STL那些先弄明白,我作业可能是做不完了,所以最后只采用c++部分基础语法知识和库函数进行程序的编写。

这段时间以来,我边玩边学,不然头都要秃掉啦!庆幸的是我昨晚得出了正确的匹配结果了,超级激动,但是他的巨无霸运行时间也给我留下了艰巨的任务...

分析学习的内容

该部分移步至另一篇博文观看—>戳这里

程序设计思路

总体程序设计思路戳这(包含关键代码、伪代码和完整代码)

这里是我的GitHub仓库地址—>戳这里

测试结果

这里使用vsc自带的比较功能,附下图(两个文件若有不同的地方会以红色高亮)
out.txt是我程序运行得出的结果;ans1.txt是作业给出的标准答案

运行时间测试的话是用clock函数先算出经历的cpu时钟的单位数,再除以每秒CPU时钟周期数常量CLOCKS_PER_SEC算出具体的秒数,如下图。

困难和学习过程

说到困难,那可太多啦!我简直天天住在csdn!

前期一些知识学习过程,请这边走!

对于后期的学习过程我将其与困难放一起写
下面是对于一些问题的描述和解决方法,希望能帮到大家,在csdn茫茫大海找解决方案实在太难受啦!

  • 关于VScode的环境配置和无法debug的问题

    • 环境配置只需要参考相关csdn博文即可
    • 对于无法debug的断点无效问题
      • csdn上很多写说要改launch.json和tasks.json的内容
      • 但其实只要将你的文件路径中的中文改成英文即可
      • 除此之外,很多情况下不管是code runner崩掉还是无法debug,重启VScode是一个非常方便的选择,可能是因为我找不出他崩掉的原因(死循环等等)
  • 关于多次重定向文件IO流,第二次及以上的重定向无效的问题

    • 查阅无数csdn博文发现:多次重定向后,cin的状态其实没有改变,需要在freopen语句前加一句cin.clear();,清空cin缓冲区,也会改变cin的状态,这样子多次重定向就都能用了
  • 关于流同步和重定向的矛盾问题

    • 刚开始为了加快cin和cout的IO速度,关掉了流同步,导致重定向无法使用,这是在逐步猜想和采取提取部分代码进行单元测试后才发现的
  • 还有关于while(cin>>a>>b){...}此类循环的结束条件的判断

    • 在文件IO中,例如a是int型,而文件中光标后非int,则该while语句就会直接跳过,不予执行,以及文件中的空格和制表符不会作为一个char类型读入,这两个问题导致我多次不能正常读取数据包和规则集内容
  • 关于再次重定向打开数据包文件后,每次光标都会回到文件首,无法依次读取所有的数据信息的问题

    • 所以采用如下方法解决:
    • 定义文件类型指针指向重定向流FILE \*p=freopen("input.txt","r",stdin);和定义文件内部指针fpos_t fp;
    • 每次读取完数据后,使用函数fgetpos(p,&fp);获取此时光标位置
    • 每次将要读取数据时,使用函数fsetpos(p,&fp);来将光标恢复至上一次结束的地方,再继续读入数据
  • 关于IP地址和协议的进制转换的困难

    • 使用非标准函数ltoa()
    • 手写一个进制转换的函数(注意:转换成二进制的时候,如果其数字太小,则其二进制位数会少于8位,所以应该手写将其补全,避免匹配出错)
  • 关于使用命令行运行程序以及加载数据包、规则集文件进行文件IO

    • 我写完程序才发现,我写的与作业想要的,彻彻底底是背道而驰了
    • 作业要求的应该是在程序中仍然使用标准输入,对于文件IO则通过cmd的命令来操作
    • 而我则是使用freopen在程序内将读写直接重定向到目标文件,然而这有个很麻烦的问题,就是如果数据包文件太多的话,我只有两种方法:
      • 第一种:将代码复制n遍,对于每次复制的代码只改动freopen的文件名参数,但是这样子代码重复率非常非常高,显得很傻而且效率低下
      • 第二种:将代码编译出.exe文件后改变freopen的文件名参数,然后再继续编译.exe文件,之后使用cmd依次执行所有的.exe文件,问题是这样子也非常的呆,很不方便
        • 对于第二种方法,其实是可以使用Makefile的方法,将所有的cmd命令存在一个文件中,然后再利用Makefile文件对其进行解析,让它替我们去执行程序!!但是这个我没学我不会呀!!还得学Makefile的新语言,不切实际!
  • 关于所有规则都不匹配输出-1的情况

    • 原本我使用的是等while(cin>>x){...}读入EOF来作为判断依据,结果也不知道为啥,它没办法读到EOF
    • 接着,我使用了feof()函数来判断,但是还是没能判断出文件末,实在也找不到原因在哪
    • 最后我利用了while(cin>>x){...}遇到不正确类型的字符不会进入循环的特点和利用变量cnt对已读规则进行计数,并在rule1.txt文件中发现规则数是918,就用cnt和918的大小关系来判断是否读到文件末
  • 对于cin>>x>>x;不能连续读入同一个变量的问题

    • 这个原因是啥我也不太清楚,但是反正cin>>x>>x;这样子不能根据需求读入x的值
    • 需要改成cin>>x,cin>>x;或者是取不同变量名cin>>x>>y;
  • 对于字符数组复制和拼接操作很麻烦的问题

    • 这边建议使用C++的string来定义,其也可以作为数组来使用,而且其能够利用加法运算进行字符串拼接等,确实方便很多
    • 但是就是有些类似ltoa的函数其传入参数必须是字符数组,可能会导致无法使用某些函数
  • 对于文件头的定义的小建议

    • 我是直接贴C++万能头#include<bits/stdc++.h>确实方便很多,不用写一整排的文件头

优化

目前的优化思路:

  • 在IP地址的匹配过程中,我原本采取的是将数据包和规则集的IP地址块都转换成二进制数,然后对前n位的网络前缀用for循环进行逐位比较,以返回值0/1判断结果
  • 改进:先得出规则集的IP地址块的最小和最大地址,将其转换成十进制数,直接判断数据包的IP地址是否处在其区间范围内,这样可以省去每一次的for循环,减小程序的时间复杂度至O(n^2),则有望将运行时间减少至1秒内(别人好像就是这样的)。

谢谢你看到了最后!如果以上内容对你有帮助,请自取;若有一些好的建议或者优化方法,或者发现了什么错误,请向我指正!特别谢谢啦!

posted @ 2022-01-29 20:18  黄锴  阅读(78)  评论(1编辑  收藏  举报