第二次寒假作业 学习历程及实操
第二次寒假作业 学习历程及实操
Part#1 需要学习什么
- 各种网络层概念和路由器的工作原理
- C++程序设计(文件读入、输出)及其优化(利用函数模块化、时空间优化)
- 规则集和数据集中的内容是什么意思,怎么将它们输入C++程序并输出正确结果
- 知识拓展
Part#2 资料找寻
看到寒假作业的要求真的是一脸懵逼,为什么简单程序都不一定会编就要开始制作软件层面的路由器了???
我先找了一圈资料...
图解 | 原来这就是网络 - 闪客sun - 博客园 (cnblogs.com)
计算机网络模型(TCP五层模型) - 知乎 (zhihu.com)
fstream的使用方法 - Boblim - 博客园 (cnblogs.com)
C++基础——文件逐行读取与字符匹配 - DECHIN - 博客园 (cnblogs.com)
P.S. 百度这些专业名词出来的东西都很杂乱...资料不好找啊...
Part#3 程序制作
先梳理一下这个程序要有什么部分
- 从文件输入数据
- 将数据集中的IP和规则集中的IP转换成同一个进制
- 协议号的进制转换
- 对数据集和规则集中的数据进行匹配和判断
- 输出结果到文件
实操部分
除了输入数据的部分一直没有办法弄好,其他部分经测试都是正确的。
声明
#include<iostream>
#include<math.h>
#include<fstream>
using namespace std;
没有什么好说的,math.h库是为了使用pow函数;我使用fstream库中的函数来进行文件流输入输出。
定义
我使用了struct来定义数据集和规则集,比较好分辨各种数据名的含义。不过打代码的速度比较慢(虽然我已经简写了)。
//定义部分
struct dataset //数据集
{
long ipin,ipout;
int ptin,ptout; //port端口
int ptcl; //protocol协议号
}dt[10001];
struct ruleset //规则集
{
int iip[5],oip[5];
long long ipin,ipout; //将带“.”的IP字符串转化为整数进行比较
int smin,smout; //subnet mask子网掩码
int ptinlow,ptinup,ptoutlow,ptoutup; //端口上下限
char ptcl[10]={};
int ptclmode,ptcll=256;
}rl[10001];
IP转换
IP转换函数,这是已经优化过后的版本:
//数据转化函数
long long iptrans(int *ip) //输入ip的四个部分,输出32位地址的十进制表示
{
long long tmp=0,result=0;
int a[4];
a[0]=ip[0];
a[1]=ip[1];
a[2]=ip[2];
a[3]=ip[3]; //直接对地址进行处理会出错所以要转换
for(int i=3;i>=0;i--) //将四个部分转化为二进制
{
tmp=0;
for(int j=0;a[i]!=0;j++)
{
tmp+=((a[i]%2)*pow(10,j));
a[i]/=2;
}
for(int j=0;tmp!=0;j++)
{
result+=(tmp%10)*pow(2,j+(i*8));
tmp/=10;
}
}
return result;
}
实际上,我最开始编写的(传统转换方法)函数是这样的:
long long iptrans(int *ip) //输入ip的四个部分,输出32位地址的十进制表示
{
long long num=0,result=0;
int a[4];
a[0]=ip[0];
a[1]=ip[1];
a[2]=ip[2];
a[3]=ip[3]; //直接对地址进行处理会出错所以要转换
for(int i=3;i>=0;i++) //将四个部分转化为二进制
{
for(int j=0;a[i]!=0;j++)
{
num+=(a[i]%2*pow(10,i));
a[i]/=2;
}
num+=pow(10,8*i); //连接四个部分
}
for(int i=0;num!=0;i++) //将32位地址转化为10进制
{
result+=(num%10)*pow(2,i);
num/=10;
}
return result;
}
但是这个代码的错误在于:
即使是long long类型的数据也没有办法容纳32位数字,所以会溢出出错。所以干脆省去了中间这个过程。
主函数部分(有未解决的错误)
//主函数
int main()
{
char tmp;
int i;
ifstream fin("rule.txt");
for(i=0;!fin.eof();i++)
{
fin>>tmp>> rl[i].iip[3]>>tmp>>rl[i].iip[2]>>tmp>>rl[i].iip[1]>>tmp>>rl[i].iip[0]>>tmp>>rl[i].smin;
fin>> rl[i].oip[3]>>tmp>>rl[i].oip[2]>>tmp>>rl[i].oip[1]>>tmp>>rl[i].oip[0]>>tmp>>rl[i].smout;
fin>>rl[i].ptinlow>>tmp>>rl[i].ptinup>>rl[i].ptoutlow>>tmp>>rl[i].ptoutup;
//fin.seekg(1,ios::cur);
//发现加上这句的时候第一行的读入会出错(第二行及后面的不会),不过字符串的第一个字符就变成空格或tab,问题不大
fin.get(rl[i].ptcl,10,'\n'); //出错点就在这句
fin.seekg(1,ios::cur);
rl[i].ipin =iptrans(rl[i].iip);
rl[i].ipout =iptrans(rl[i].oip);
if(rl[i].ptcl[8]=='F'&&rl[i].ptcl[9]=='F')
{
rl[i].ptclmode=0;
rl[i].ptcll=(((int)rl[i].ptcl[3])-48)*10+((int)rl[i].ptcl[4])-48;
}
else if(rl[i].ptcl[8]=='0'&&rl[i].ptcl[9]=='0')
{
rl[i].ptclmode=1;
}
}
ifstream dfin("packet.txt");
ofstream fout("ans.txt");
for(int j=0;!dfin.eof();j++)
{
dfin>>dt[j].ipin>>dt[j].ipout>>dt[j].ptin>>dt[j].ptout>>dt[j].ptcl;
for(int k=0;k<i;k++)
{
if(dt[j].ipin==rl[k].ipin&&dt[j].ipout==rl[k].ipout)
{
if(dt[j].ptin<=rl[k].ptinup&&dt[j].ptin>=rl[k].ptinlow&&dt[j].ptout<=rl[k].ptoutup&&dt[j].ptout>=rl[k].ptoutlow)
{
if(dt[j].ptcl==rl[k].ptcll||rl[k].ptclmode)
{
fout<<k<<endl;
break;
}
}
}
}
}
return 0;
}
出错的句子是:fin.get(rl[i].ptcl,10,'\n');
出错的表现是:执行完这个命令之后,ptcl字符串是:(\t)0x06/0xFF
(符合预期),但是文件读入指针停在了下一行,导致下一次读入时,IP从178.139.217.251变成了78.139.217.251甚至是8.139.217.251。
教程中对这个函数的描述是:
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim=’\n’);这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符’\n’。例如:
file2.get(str1,127,’A’); //从文件中读取字符到字符串str1,当遇到字符’A’或读取了127个字符时终止。
但是这个问题没有办法通过调节10
和\n
两个参数使输入结果正确。并且,178变成78或者8的规律并不能找到。
其他同学的抱怨:
我在使用C++ STL的fstream中遇到了很多问题,ifstream有时候会多读最后一个空行,有时候又不会,毫无规律可循。上网搜索办法五花八门,均无明显作用,我只能手动标记来减少读入错误的情况。以前别人说C++ STL残疾我不信,现在我信了。很难不让人怀疑这个标准库本身的实现是否就存在问题。
Part#4 后记
这次作业着实是个挑战。看到同班同学都能够很好的完成,并且展示出了比我更高的技巧,我自愧不如。接下来还要好好学习计算机方面的知识。虽然没有完全完成这项作业,但是我了解了很多网络层的知识,学习了文件流的基本使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?