3 DHCP服务器
因为是个大模拟,题目又臭又长还有点儿绕,解答本题要好好理解题意,按照题目要求来写。
题意
DHCP 数据报文的格式:
<发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
string string DIS
* OFR
REQ
ACK
NAK
Round 1
代码按照题目给出的细节要求一步步进行即可,但是需要注意一些细节处理,例如条件之间的关系该用与还是或。
问题主要出现在这个地方:out给出的是过期的时刻,所以这里要判断 过期时间是否超过上下限
注意到:样例解释中的 第 13、14 个报文中,e 试图请求地址。此时地址池中已经没有处于“未分配”状态的地址了,但是有此前分配给 b 的地址 2 的状态是“过期”,因此把该地址重新分配给 e。
就可以发现 你忘记处理过期的地址池了。
根据:
在处理每条命令前,要处理一下过期的IP:
等会儿!!! 这里 过期时刻应该是 ip[i].out<=t
而不是刚刚好=!!!你要没发现的话 又该要debug很久了???你写啥呢???大模拟最重要的就是细节啊!!! 仔细点儿!!!
Round 2
进行了以上修改后,基本上可以得到比较好的结果了,如下结果基本正确,但最后一条命令没能读入处理???
此时得分只有40分,那么 为什么会提前终止了呢???
啊 笨蛋 让你乱用 break
,
因为这里有个 break
,刚好你第15个命令就走到了这里…然后break出读命令的循环了…
![在这里插入图片描述](https://www.icode9.com/i/ll/?i=d1137b5dcebc43adb1cb50e0589e2978.png = 500x)
噗 改完这个bug还是只有60分…样例能过了,但肯定还存在其他没有考虑到的细节!!!
Round 3
噗噗…吐得一脸好血…
这里这里…
debug de那么久…没发现是应该 ip[j].own==send
吗…之前写的是 ==recieve
啊老天鹅…这要不是对了一遍算法流程还真发现不了?
我还是太粗心了…
完整代码
//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1e4+5;
struct node{
int state;// 0未分配 1待分配 2占用 3过期
int out;//过期时刻
string own;//占用者
}ip[maxn];
int main()
{
int N,tdef,tmax,tmin,n;
string H;
cin>>N>>tdef>>tmax>>tmin>>H;
for(int i=1;i<=N;i++)
{
ip[i].state=0;
ip[i].out=0;
ip[i].own="";
}
cin>>n;
for(int k=0;k<n;k++)
{
string send,receive,type;
int address,t,out;
//<收到报文时刻> <发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
cin>>t>>send>>receive>>type>>address>>out;
//cout<<"y "<<t<<endl;
//cout<<"i "<<t<<" "<<send<<" "<<receive<<" "<<type<<" "<<address<<" "<<out<<endl;
//cout<<"-!-"<<endl;
//cout<<type<<endl;
for(int i=1;i<=N;i++)//遍历所有IP
{
if(ip[i].state==1&&ip[i].out<=t) //如果过期时刻比当前时刻早
{
ip[i].state=0;
ip[i].own="";
ip[i].out=0;
}else if(ip[i].state==2&&ip[i].out<=t)
{
ip[i].state=3;
ip[i].out=0;
}else if(ip[i].state==3||ip[i].state==0)
{
ip[i].out=0;
}
}
if((receive!=H&&receive!="*")&&type!="REQ") // 同理 这里的也应该是&& 而且之前放错位置了!这个应该在第一个进行判断
continue;
//这样也是ok的
if(type!="REQ"&&type!="DIS") //你怎么能在这用||呢?这样满足第一个条件就算是DIS也会continue掉
continue;
//if(type=="REQ"||type=="DIS")
//{
if((receive=="*"&&type!="DIS")||(receive==H&&type=="DIS"))
continue;
if(type=="DIS")
{
int rip=-1;
for(int j=1;j<=N;j++)
{
if(ip[j].state&&ip[j].own==send) // 只要不是0未分配状态,就都有占用者
{
rip=j;
break;
}
}
if(rip==-1) // 若没有,则选取最小的状态为未分配的 IP 地址;
{
for(int j=1;j<=N;j++)
{
if(!ip[j].state)
{
rip=j;
break;
}
}
}
if(rip==-1) // 若没有,则选取最小的状态为过期的 IP 地址;
{
for(int j=1;j<=N;j++)
{
if(ip[j].state==3)
{
rip=j;
break;
}
}
}
if(rip!=-1) // 找到了可用ip,可继续处理
{
ip[rip].state=1;
ip[rip].own=send;
if(out==0)
ip[rip].out=t+tdef;
else if(out-t>=tmax)
ip[rip].out=t+tmax;
else if(out-t<=tmin)
ip[rip].out=t+tmin;
else
ip[rip].out=out;
cout<<H<<" "<<send<<" OFR "<<rip<<" "<<ip[rip].out<<endl;
}
//if(rip==-1)
//cout<<"not enough"<<endl;
}else if(type=="REQ")
{
if(receive!=H) //发给非本服务器的 不予应答
{
for(int j=1;j<=N;j++)
{
if(ip[j].own==send&&ip[j].state==1)
{
ip[j].state=0;
ip[j].own="";
ip[j].out=0;
}
}
}else //注意后半部分要包在else里
{
//if(!(address>=1&&address<=N&&ip[address].own==send))
if(address<1||address>N||ip[address].own!=send)
{
cout<<H<<" "<<send<<" NAK "<<address<<" 0"<<endl;
}else{
ip[address].state=2;
if(out==0)
ip[address].out=t+tdef;
else if(out-t>tmax) // ???你脑子瓦特啦 out-t 才是有效时间,out给出的是过期时刻
ip[address].out=t+tmax;
else if(out-t<tmin)
ip[address].out=t+tmin;
else
ip[address].out=out;
cout<<H<<" "<<send<<" ACK "<<address<<" "<<ip[address].out<<endl;
}
}
}
//}
}
//cout<<"out"<<endl;
return 0;
}
总结
大模拟需要的就是耐心和仔细,其实并不难,但是如果不注意的话,写bug的概率会比较大,就像笔者上面干的蠢事一样…2333
其实可以不看原理部分,而是直接从实施细节开始就好了,前面都没啥用2333,但当然 你要知道一点DHCP工作原理啦…当然不知道其实也可以,一步步按照细节说的去写流程代码就好啦。
最后 还是 细节 细节 细节!!!