栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

CCF-CSP-202104-3:DHCP服务器(C++11题解)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

CCF-CSP-202104-3:DHCP服务器(C++11题解)

文章目录
  • 问题描述
  • 解题思路
    • 报文格式
    • 报文处理
    • 服务器时钟更新
  • AC代码

问题描述
  • 题目来源:CCF-CSP-202104-3:DHCP服务器
解题思路 报文格式

    根据题目的要求,报文的格式为:<发送主机> <接收主机> <报文类型> <过期时刻>。报文格式的要求如题目所述。
    但是,我们从示例中还看出了一些需要特别注意的地方:

  • REQ报文的接收者不能是"*"(即所有主机)。
  • DIS报文的接收者必须是"*"(即所有主机)。
报文处理

    DHCP服务器在处理接收到的报文(DHCP::DHCPPool::HandlePkt函数)时的主要逻辑如下:

  • DIS报文:将格式正确的报文交由DHCP::DHCPPool::HandleDISPkt函数处理。
  • OFR报文:不处理。
  • REQ报文:
    • 将格式正确的报文且接收主机为本机的报文交由DHCP::DHCPPool::HandleREQPkt函数处理。
    • 将格式正确的报文且接收主机为非本机的报文交由DHCP::DHCPPool::HandleOtherREQPkt函数处理。
  • ACK报文:不处理。
  • NAK报文:不处理。
服务器时钟更新

    在RecvClock时刻接收到报文时,及时对服务器时间进行更新,并以此对过期IP的状态、拥有者、过期时间等信息进行更新。

AC代码

关于编码风格的说明:习惯性地使用了一些面向对象的思想对代码进行封装。实际考试时考虑到编码效率,可能没必要这么做。

#include 
#include 
#include 

namespace DHCP
{
    enum class DHCPPktEnumType
    {
        DIS, OFR, REQ, ACK, NAK
    };

    std::istream &operator>> (std::istream &Istream, DHCPPktEnumType &PktType)
    {
        std::string DHCPPktTypeStr;
        Istream >> DHCPPktTypeStr;

        do
        {
            if(DHCPPktTypeStr == "DIS") { PktType = DHCPPktEnumType::DIS; break; }

            if(DHCPPktTypeStr == "OFR") { PktType = DHCPPktEnumType::OFR; break; }

            if(DHCPPktTypeStr == "REQ") { PktType = DHCPPktEnumType::REQ; break; }

            if(DHCPPktTypeStr == "ACK") { PktType = DHCPPktEnumType::ACK; break; }

            if(DHCPPktTypeStr == "NAK") { PktType = DHCPPktEnumType::NAK; break; }
        }
        while(false);

        return Istream;
    }

    using HostNameType = std::string;
    using IPAddrType = unsigned int;
    using TimeoutType = size_t;

    class DHCPPkt
    {
    public:
        DHCPPkt() = default;

        bool isCorrectDISPkt() const
        {
            return m_PktType == DHCPPktEnumType::DIS && m_HostRecv == "*";
        }

        bool isCorrectREQPkt() const
        {
            return m_PktType == DHCPPktEnumType::REQ && m_HostRecv != "*";
        }

        friend std::istream &operator>>(std::istream &Istream, DHCPPkt &Pkt)
        {
            Istream >> Pkt.m_HostSend >> Pkt.m_HostRecv >> Pkt.m_PktType >> Pkt.m_IPAddr >> Pkt.m_Timeout;

            return Istream;
        }

    public:
        HostNameType m_HostSend;
        HostNameType m_HostRecv;
        DHCPPktEnumType m_PktType;
        IPAddrType m_IPAddr;
        TimeoutType m_Timeout;
    };

    using SizeType = size_t;

    class DHCPPool
    {
    private:
        class IPInfo
        {
        public:
            enum class IPStatus
            {
                UnAssigned, ToBeAssigned, Occupied, Expired
            };

            IPInfo(IPAddrType IPAddr): m_IPAddr(IPAddr), m_IPStatus(IPStatus::UnAssigned), m_Timeout(0) {}

        public:
            IPAddrType m_IPAddr;
            IPStatus m_IPStatus;
            HostNameType m_Owner;
            TimeoutType m_Timeout;
        };

    private:
        const std::string m_ServerName;
        const SizeType m_PoolSize;
        const TimeoutType m_TimeoutDef, m_TimeoutMin, m_TimeoutMax;
        std::vector m_IPInfoVector;
        TimeoutType m_Time;

    public:
        DHCPPool(std::string ServerName, SizeType PoolSize, TimeoutType TimeoutDef, TimeoutType TimeoutMin, TimeoutType TimeoutMax)
            : m_ServerName(ServerName), m_PoolSize(PoolSize),
              m_TimeoutDef(TimeoutDef), m_TimeoutMin(TimeoutMin), m_TimeoutMax(TimeoutMax),
              m_Time(0)
        {
            m_IPInfoVector.reserve(m_PoolSize);
            for(SizeType i = 1; i <= m_PoolSize; ++i)
            {
                m_IPInfoVector.emplace_back(static_cast(i));
            }
        }

    public:
        void UpdateTime(TimeoutType Time)
        {
            m_Time = Time;

            for(IPInfo &IPInfo_i : m_IPInfoVector)
            {
                if(IPInfo_i.m_Timeout == 0 || IPInfo_i.m_Timeout > Time) continue;

                do
                {
                    if(IPInfo_i.m_IPStatus == IPInfo::IPStatus::ToBeAssigned)
                    {
                        IPInfo_i.m_IPStatus = IPInfo::IPStatus::UnAssigned;
                        IPInfo_i.m_Owner.clear();
                        IPInfo_i.m_Timeout = 0;
                        break;
                    }

                    if(IPInfo_i.m_IPStatus == IPInfo::IPStatus::Occupied)
                    {
                        IPInfo_i.m_IPStatus = IPInfo::IPStatus::Expired;
                        IPInfo_i.m_Timeout = 0;
                        break;
                    }
                }
                while(false);
            }
        }

        void HandlePkt(const DHCPPkt &Pkt)
        {
            do
            {
                if(Pkt.m_PktType == DHCPPktEnumType::DIS)
                {
                    if(Pkt.isCorrectDISPkt()) HandleDISPkt(Pkt);
                    break;
                }

                if(Pkt.m_PktType == DHCPPktEnumType::REQ)
                {
                    if(Pkt.isCorrectREQPkt())
                    {
                        if(Pkt.m_HostRecv == m_ServerName) HandleREQPkt(Pkt);
                        else HandleOtherREQPkt(Pkt);
                    }

                    break;
                }
            }
            while(false);
        }

    private:
        inline SizeType GetIPAddrIndex(IPAddrType IPAddr)
        {
            return static_cast(IPAddr - 1);
        }

        inline GetTimeout(const DHCPPkt &Pkt)
        {
            if(Pkt.m_Timeout == 0) return m_Time + m_TimeoutDef;

            if(Pkt.m_Timeout < m_Time + m_TimeoutMin) return m_Time + m_TimeoutMin;

            if(Pkt.m_Timeout > m_Time + m_TimeoutMax) return m_Time + m_TimeoutMax;

            return Pkt.m_Timeout;
        }

        void OfferIP(IPInfo &IPInfoOffered, const DHCPPkt &Pkt)
        {
            IPInfoOffered.m_IPStatus = IPInfo::IPStatus::ToBeAssigned;
            IPInfoOffered.m_Owner = Pkt.m_HostSend;
            IPInfoOffered.m_Timeout = GetTimeout(Pkt);

            SendOfferPkt(IPInfoOffered, Pkt);
        }

    private:
        inline void SendOfferPkt(const IPInfo &IPInfoOffered, const DHCPPkt &Pkt)
        {
            std::cout << m_ServerName << ' ' << Pkt.m_HostSend << " OFR " << IPInfoOffered.m_IPAddr << ' ' << IPInfoOffered.m_Timeout << std::endl;
        }

        inline void SendACKPkt(const IPInfo &IPInfoRequested, const DHCPPkt &Pkt)
        {
            std::cout << m_ServerName << ' ' << Pkt.m_HostSend << " ACK " << IPInfoRequested.m_IPAddr << ' ' << IPInfoRequested.m_Timeout << std::endl;
        }

        inline void SendNAKPkt(const DHCPPkt &Pkt)
        {
            std::cout << m_ServerName << ' ' << Pkt.m_HostSend << " NAK " << Pkt.m_IPAddr << " 0" << std::endl;
        }

    private:
        void HandleDISPkt(const DHCPPkt &Pkt)
        {
            // find the first IP address whose owner is the host that sent this packet
            for(IPInfo &IPInfo_i : m_IPInfoVector)
            {
                if(IPInfo_i.m_Owner == Pkt.m_HostSend)
                {
                    OfferIP(IPInfo_i, Pkt);
                    return;
                }
            }

            // find the first unassigned IP address
            for(IPInfo &IPInfo_i : m_IPInfoVector)
            {
                if(IPInfo_i.m_IPStatus == IPInfo::IPStatus::UnAssigned)
                {
                    OfferIP(IPInfo_i, Pkt);
                    return;
                }
            }

            // find the first expired IP address
            for(IPInfo &IPInfo_i : m_IPInfoVector)
            {
                if(IPInfo_i.m_IPStatus == IPInfo::IPStatus::Expired)
                {
                    OfferIP(IPInfo_i, Pkt);
                    return;
                }
            }
        }

        void HandleREQPkt(const DHCPPkt &Pkt)
        {
            if(Pkt.m_IPAddr > m_PoolSize)
            {
                SendNAKPkt(Pkt);
                return;
            }

            IPInfo &IPInfoRequested = m_IPInfoVector[GetIPAddrIndex(Pkt.m_IPAddr)];

            if(IPInfoRequested.m_Owner != Pkt.m_HostSend)
            {
                SendNAKPkt(Pkt);
                return;
            }

            IPInfoRequested.m_IPStatus = IPInfo::IPStatus::Occupied;
            IPInfoRequested.m_Timeout = GetTimeout(Pkt);

            SendACKPkt(IPInfoRequested, Pkt);
        }


        void HandleOtherREQPkt(const DHCPPkt &Pkt)
        {
            for(IPInfo &IPInfo_i : m_IPInfoVector)
            {
                if(IPInfo_i.m_Owner == Pkt.m_HostSend && IPInfo_i.m_IPStatus == IPInfo::IPStatus::ToBeAssigned)
                {
                    IPInfo_i.m_IPStatus = IPInfo::IPStatus::UnAssigned;
                    IPInfo_i.m_Owner.clear();
                    IPInfo_i.m_Timeout = 0;
                }
            }
        }
    };
}

int main()
{
    // IO initialization
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    // DHCP pool configuration
    DHCP::SizeType DHCPPoolSize;
    DHCP::TimeoutType TimeoutDef, TimeoutMin, TimeoutMax;
    std::string DHCPServerName;

    std::cin >> DHCPPoolSize;
    std::cin >> TimeoutDef >> TimeoutMax >> TimeoutMin;
    std::cin >> DHCPServerName;

    // create DHCP pool
    DHCP::DHCPPool LocalDHCPPool(DHCPServerName, DHCPPoolSize, TimeoutDef, TimeoutMin, TimeoutMax);

    int DHCPPktNum;
    std::cin >> DHCPPktNum;

    // input packet and then cope with it
    for(int Pkt_i = 0; Pkt_i < DHCPPktNum; ++Pkt_i)
    {
        size_t RecvClock;
        DHCP::DHCPPkt Pkt;

        std::cin >> RecvClock >> Pkt;

        // update the inside clock of DHCP pool
        LocalDHCPPool.UpdateTime(RecvClock);

        // handle each packet
        LocalDHCPPool.HandlePkt(Pkt);
    }

    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983187.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号