1. 程式人生 > 其它 >202104-3 DHCP伺服器

202104-3 DHCP伺服器

在 DHCP 啟動時,首先初始化 IP 地址池,將所有地址設定狀態為未分配,佔用者為空,並清零過期時刻

其中地址的狀態有未分配、待分配、佔用、過期四種。

處於未分配狀態的 IP 地址沒有佔用者,而其餘三種狀態的 IP 地址均有一名佔用者。

處於待分配和佔用狀態的 IP 地址擁有一個大於零的過期時刻。

在當前時刻傳送報文時,首先更新當前時刻IP池中IP地址的狀態。在到達該過期時刻時若該地址的狀態是待分配,則該地址的狀態會自動變為未分配,且佔用者清空,過期時刻清零;否則該地址的狀態會由佔用自動變為過期,且過期時刻清零

處於未分配和過期狀態的 IP 地址過期時刻為零,即沒有過期時刻

對於收到的報文,設其收到的時刻為 t。處理細節如下:

  1. 判斷接收主機是否為本機,或者為 *,若不是,則判斷型別是否為 Request,若不是,則不處理;
  2. 若型別不是 Discover、Request 之一,則不處理;
  3. 若接收主機為 *,但型別不是 Discover,或接收主機是本機,但型別是 Discover,則不處理。

對於 Discover 報文,按照下述方法處理:

  1. 檢查是否有佔用者為傳送主機的 IP 地址:
    • 若有,則選取該 IP 地址;
    • 若沒有,則選取最小的狀態為未分配的 IP 地址;
    • 若沒有,則選取最小的狀態為過期的 IP 地址;
    • 若沒有,則不處理該報文,處理結束;
  2. 將該 IP 地址狀態設定為待分配,佔用者設定為傳送主機
  3. 若報文中過期時刻為 0 ,則設定過期時刻為 t+Tdef
    ;否則根據報文中的過期時刻和收到報文的時刻計算過期時間,判斷是否超過上下限:若沒有超過,則設定過期時刻為報文中的過期時刻;否則則根據超限情況設定為允許的最早或最晚的過期時刻;
  4. 向傳送主機發送 Offer 報文,其中,IP 地址為選定的 IP 地址,過期時刻為所設定的過期時刻。

對於 Request 報文,按照下述方法處理:

  1. 檢查接收主機是否為本機:
    • 若不是,則找到佔用者為傳送主機的所有 IP 地址,對於其中狀態為待分配的,將其狀態設定為未分配,並清空其佔用者,清零其過期時刻,處理結束;
  2. 檢查報文中的 IP 地址是否在地址池內,且其佔用者為傳送主機,若不是,則向傳送主機發送 Nak 報文,處理結束;
  3. 無論該 IP 地址的狀態為何,將該 IP 地址的狀態設定為佔用;
  4. 與 Discover 報文相同的方法,設定 IP 地址的過期時刻;
  5. 向傳送主機發送 Ack 報文。
enum State {
    unassigned, to_be_assigned, occupy, overdue
};
struct IP {
    State state;
    string occupier;
    int deadtime;
} ip[N];
int n, m, Tdef, Tmax, Tmin;
string dhcpname;

void update(int curtime)
{
    for(int i = 1; i <= n; i++)
        if((ip[i].state == to_be_assigned || ip[i].state == occupy) && ip[i].deadtime <= curtime)
        {
            if(ip[i].state == to_be_assigned)
            {
                ip[i].state = unassigned;
                ip[i].occupier = "";
                ip[i].deadtime = 0;
            }
            else
            {
                ip[i].state  = overdue;
                ip[i].deadtime = 0;
            }
        }
}

int get_ip_by_occupier(string client)
{
    for(int i = 1; i <= n; i++)
        if(ip[i].occupier == client)
            return i;
    return 0;
}

int get_ip_by_state(State state)
{
    for(int i = 1; i <= n; i++)
        if(ip[i].state == state)
            return i;
    return 0;
}

int main()
{
    cin >> n >> Tdef >> Tmax >> Tmin  >> dhcpname;

    cin >> m;
    while(m--)
    {
        int curtime;
        string client, server, type;
        int ip_address, deadtime;

        cin >> curtime >> client >> server >> type >> ip_address >> deadtime;

        if(!(server == dhcpname || server == "*") && type != "REQ") continue;
        if(!(type == "DIS" || type == "REQ")) continue;
        if(server == "*" && type != "DIS" || server == dhcpname && type  == "DIS") continue;

        update(curtime);

        if(type == "DIS")
        {
            int k = get_ip_by_occupier(client);
            if(!k) k = get_ip_by_state(unassigned);
            if(!k) k = get_ip_by_state(overdue);
            if(!k) continue;
            ip[k].state = to_be_assigned, ip[k].occupier = client;
            if(deadtime == 0)
                ip[k].deadtime = curtime + Tdef;
            else
                ip[k].deadtime = min(max(deadtime, curtime + Tmin), curtime + Tmax);

            cout << dhcpname << ' ' << client << ' ' << "OFR" << ' ' << k << ' ' << ip[k].deadtime << endl;
        }
        else
        {
            if(server != dhcpname)
            {
                for(int i = 1; i <= n; i++)
                    if(ip[i].occupier == client && ip[i].state == to_be_assigned)
                    {
                        ip[i].state = unassigned;
                        ip[i].occupier = "";
                        ip[i].deadtime = 0;
                    }
            }
            else
            {
                if(ip_address >= 1 && ip_address <= n && ip[ip_address].occupier == client)
                {
                    ip[ip_address].state = occupy;
                    if(deadtime == 0)
                        ip[ip_address].deadtime = curtime + Tdef;
                    else
                        ip[ip_address].deadtime = min(max(deadtime, curtime + Tmin), curtime + Tmax);

                    cout << dhcpname << ' ' << client << ' ' << "ACK" << ' ' << ip_address << ' ' << ip[ip_address].deadtime << endl;
                }
                else
                    cout << dhcpname << ' ' << client << ' ' << "NAK" << ' ' << ip_address << ' ' << 0 << endl;
            }
        }
    }

    //system("pause");
    return 0;
}