第二次寒假作业 学习历程及实操

第二次寒假作业 学习历程及实操

Part#1 需要学习什么

  • 各种网络层概念和路由器的工作原理
  • C++程序设计(文件读入、输出)及其优化(利用函数模块化、时空间优化)
  • 规则集和数据集中的内容是什么意思,怎么将它们输入C++程序并输出正确结果
  • 知识拓展

Part#2 资料找寻

看到寒假作业的要求真的是一脸懵逼,为什么简单程序都不一定会编就要开始制作软件层面的路由器了???

我先找了一圈资料...

图解 | 原来这就是网络 - 闪客sun - 博客园 (cnblogs.com)

计算机网络模型(TCP五层模型) - 知乎 (zhihu.com)

计算机网络-学习路由器_新林的博客-CSDN博客_路由器

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 后记

这次作业着实是个挑战。看到同班同学都能够很好的完成,并且展示出了比我更高的技巧,我自愧不如。接下来还要好好学习计算机方面的知识。虽然没有完全完成这项作业,但是我了解了很多网络层的知识,学习了文件流的基本使用。

posted @ 2022-01-31 10:13  Knigh7_de_Ficusé  阅读(35)  评论(0编辑  收藏  举报