202104-3 DHCP伺服器
阿新 • • 發佈:2021-06-22
在 DHCP 啟動時,首先初始化 IP 地址池,將所有地址設定狀態為未分配,佔用者為空,並清零過期時刻。
其中地址的狀態有未分配、待分配、佔用、過期四種。
處於未分配狀態的 IP 地址沒有佔用者,而其餘三種狀態的 IP 地址均有一名佔用者。
處於待分配和佔用狀態的 IP 地址擁有一個大於零的過期時刻。
在當前時刻傳送報文時,首先更新當前時刻IP池中IP地址的狀態。在到達該過期時刻時,若該地址的狀態是待分配,則該地址的狀態會自動變為未分配,且佔用者清空,過期時刻清零;否則該地址的狀態會由佔用自動變為過期,且過期時刻清零。
處於未分配和過期狀態的 IP 地址過期時刻為零,即沒有過期時刻。
對於收到的報文,設其收到的時刻為 t。處理細節如下:
- 判斷接收主機是否為本機,或者為
*
,若不是,則判斷型別是否為 Request,若不是,則不處理; - 若型別不是 Discover、Request 之一,則不處理;
- 若接收主機為
*
,但型別不是 Discover,或接收主機是本機,但型別是 Discover,則不處理。
對於 Discover 報文,按照下述方法處理:
- 檢查是否有佔用者為傳送主機的 IP 地址:
- 若有,則選取該 IP 地址;
- 若沒有,則選取最小的狀態為未分配的 IP 地址;
- 若沒有,則選取最小的狀態為過期的 IP 地址;
- 若沒有,則不處理該報文,處理結束;
- 將該 IP 地址狀態設定為待分配,佔用者設定為傳送主機;
- 若報文中過期時刻為 0 ,則設定過期時刻為 t+Tdef
- 向傳送主機發送 Offer 報文,其中,IP 地址為選定的 IP 地址,過期時刻為所設定的過期時刻。
對於 Request 報文,按照下述方法處理:
- 檢查接收主機是否為本機:
- 若不是,則找到佔用者為傳送主機的所有 IP 地址,對於其中狀態為待分配的,將其狀態設定為未分配,並清空其佔用者,清零其過期時刻,處理結束;
- 檢查報文中的 IP 地址是否在地址池內,且其佔用者為傳送主機,若不是,則向傳送主機發送 Nak 報文,處理結束;
- 無論該 IP 地址的狀態為何,將該 IP 地址的狀態設定為佔用;
- 與 Discover 報文相同的方法,設定 IP 地址的過期時刻;
- 向傳送主機發送 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;
}