CSP202104-3 DHCP模拟

这题信息量贼大,看了Acwing网站的Y总视频后明白了一些

//这种模拟竟然属于比较简单的模拟???
//直接按照顺序敲就可以了,其实也不不是很难,主要是自己之前没有做过
//而且压根没静下心想一下,把程序想象成服务器就行了,明显需要维护的就是一个ip地址池
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=10010;//所以时间复杂度应不超过n方

int n, m, t_def, t_max, t_min;//ip地址个数, 请求个数,分配个客户端的ip地址的默认过期时间长度
//最长和最短过期时间
string h;//主机名称
struct IP
{
    int state; // 0:未分配, 1:待分配 2:占用 3:过期
    int t;//过期时间
    string owner;
}ip[N];

void update_ips_state(int tc)
{
    //对所有ip更新
    for(int i=1; i<=n; i++)
    {
        //如果ip的过期时刻大于0,并且过期了
        if(ip[i].t && ip[i].t<= tc)
        {
            //如果待分配,则状态变成未分配,且占用者清空,过期时刻清零
            if(ip[i].state == 1)
            {
                ip[i].state=0;
                ip[i].owner="";
                ip[i].t=0;
            }
            //否则该地址的状态会由占用自动变为过期,且过期时刻清零。
            else
            {
                ip[i].state=3;
                ip[i].t=0;
            }
        }
    }
}

//选取特定状态的ip
int get_ip_by_state(int state)
{
    for(int i=1; i<=n; i++)
        if(ip[i].state == state)
            return i;
    return 0; //否则返回分配失败
}

//通过client找一下有没有用过的ip
int get_ip_by_owner(string client)
{
    for(int i=1; i<=n; i++)
        if(ip[i].owner == client)
            return i;
    return 0;
}

int main()
{
    cin>>n>>t_def>>t_max>>t_min>>h;
    cin>>m;

    while(m--)
    {
        int tc;//收到报文的时间
        string client, server, type;
        int id, te;//<发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
        cin>>tc>>client>>server>>type>>id>>te;
        //按照处理细节依次处理
        //三种情况都不处理
        if(server!=h && server!="*")
        {
            if(type != "REQ") continue;
        }
        if(type != "DIS" && type!="REQ") continue;
        //确实,发*一定对应dis, 给服务器发一定不对应dIS
        if((server == "*" && type != "DIS") || (server == h && type == "DIS")) continue;

        //然后更新一下ip地址池的状态,确实,每次处理一个新的报文,都要更新状态
        update_ips_state(tc);//传入当前时刻

        //处理dis报文
        if(type == "DIS")
        {
            //检查是否有占用者为发送主机的 IP 地址:
            //若有,则选取该 IP 地址;
            int k=get_ip_by_owner(client);
            //若没有,则选取最小的状态为未分配的 IP 地址;
            if(!k) k=get_ip_by_state(0);//0是未分配
            // 若没有,则选取最小的状态为过期的 IP 地址;
            if(!k) k=get_ip_by_state(3);//过期为3
            // 若没有,则不处理该报文,处理结束
            if(!k) continue;
            //当分配到ip地址以后
            // 将该 IP 地址状态设置为待分配,占用者设置为发送主机;
            ip[k].state=1, ip[k].owner=client;

            // 若报文中过期时刻为 0 ,则设置过期时刻为 t+Tdef;
            if(!te) ip[k].t=tc+t_def;
            // 否则根据报文中的过期时刻和收到报文的时刻计算过期时间,
            // 判断是否超过上下限:若没有超过,则设置过期时刻为报文中
            // 的过期时刻;否则则根据超限情况设置为允许的最早或最晚的过期时刻;
            else
            {
                int t= te- tc;//想使用的时间长度
                t=max(t, t_min), t=min(t, t_max);
                //t既不能小于最低时间,也不能超过最长时间
                ip[k].t=tc+t;
            }
            //应该发送OFFER报文了
            cout<< h << " " << client << ' ' <<"OFR" <<' ' <<  k << ' ' <<ip[k].t <<endl;
        }
        //处理request请求
        else 
        {
            //如果接受者不是本机
            if (server != h)
            {
                // 到占用者为发送主机的所有 IP 地址,对于其中状态为待分配的,将其状态设置为未分配,并清空其占用者,清零其过期时刻,处理结束;
                for(int i=1; i<=n; i++)
                {
                    if(ip[i].owner == client && ip[i].state == 1)
                    {
                        ip[i].state = 0;
                        ip[i].owner= "";
                        ip[i].t=0;
                    }
                }
                continue;
            }
            // 检查报文中的 IP 地址是否在地址池内,若不是,则向发送主机发送 Nak 报文,处理结束;
            if(!(id>=1 && id<=n && ip[id].owner == client))
                cout << h << ' ' << client << ' ' <<"NAK" <<" " << id <<' '<<0 <<endl;
            //如果在地址池内
            else
            {
                // 无论该 IP 地址的状态为何,将该 IP 地址的状态设置为占用;
                ip[id].state=2;
                // 与 Discover 报文相同的方法,设置 IP 地址的过期时刻;
                if(!te) ip[id].t=tc+t_def;
                else
                {
                    int t= te- tc;//想使用的时间长度
                    t=max(t, t_min), t=min(t, t_max);
                    //t既不能小于最低时间,也不能超过最长时间
                    ip[id].t=tc+t;
                }
                //应该发送报文了
                cout<< h <<' '<<client <<' '<<"ACK" <<' '<<id <<' ' <<ip[id].t <<endl;
            }

        }
    }

    return 0;
}


本文参考了https://www.acwing.com/solution/content/46032/

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值