问题描述
试题编号: | 202104-3 |
试题名称: | DHCP服务器 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 试题背景动态主机配置协议(Dynamic Host Configuration Protocol, DHCP)是一种自动为网络客户端分配 IP 地址的网络协议。当支持该协议的计算机刚刚接入网络时,它可以启动一个 DHCP 客户端程序。后者可以通过一定的网络报文交互,从 DHCP 服务器上获得 IP 地址等网络配置参数,从而能够在用户不干预的情况下,自动完成对计算机的网络设置,方便用户连接网络。DHCP 协议的工作过程如下:
在本题目中,你需要理解 DHCP 协议的工作过程,并按照题目的要求实现一个简单的 DHCP 服务器。 问题描述报文格式为了便于实现,我们简化地规定 DHCP 数据报文的格式如下: None DHCP 数据报文的各个部分由空格分隔,其各个部分的定义如下:
例如下列都是合法的 DHCP 数据报文: None 服务器配置为了 DHCP 服务器能够正确分配 IP 地址,DHCP 需要接受如下配置:
分配策略当客户端请求 IP 地址时,首先检查此前是否给该客户端分配过 IP 地址,且该 IP 地址在此后没有被分配给其它客户端。如果是这样的情况,则直接将 IP 地址分配给它,否则, 实现细节在 DHCP 启动时,首先初始化 IP 地址池,将所有地址设置状态为未分配,占用者为空,并清零过期时刻。 对于收到的报文,设其收到的时刻为 t。处理细节如下:
对于 Discover 报文,按照下述方法处理:
对于 Request 报文,按照下述方法处理:
上述处理过程中,地址池中地址的状态的变化可以概括为如下图所示的状态转移图。为了简洁,该图中没有涵盖需要回复 Nak 报文的情况。 输入格式输入的第一行包含用空格分隔的四个正整数和一个字符串,分别是:N、Tdef、Tmax、Tmin 和 H,保证 Tmin≤Tdef≤Tmax。 输入的第二行是一个正整数 n,表示收到了 n 个报文。 输入接下来有 n 行,第 (i+2) 行有空格分隔的正整数 ti 和约定格式的报文 Pi。表示收到的第 i 个报文是在 ti 时刻收到的,报文内容是 Pi。保证 ti<ti+1。 输出格式输出有若干行,每行是一个约定格式的报文。依次输出 DHCP 服务器发送的报文。 样例输入 Data 样例输出 Data 样例说明输入第一行,分别设置了 DHCP 的相关参数,并收到了 16 个报文。 第 1 个报文和第 2 个报文是客户端 第 3 个报文不符合 Discover 报文的要求,不做任何处理。 第 4 个报文 第 5 个报文中,Request 报文不符合接收主机是 DHCP 服务器本机的要求,因此不做任何处理。 第 6 个报文是 第 7 个报文中,过期时刻 11 小于最短过期时间,因此返回的过期时刻是 12。虽然此时为 第 9、10 两个报文中,为 第 11 个报文中, 第 12 个报文中, 第 13、14 个报文中, 第 15 个报文中, 第 16 个报文中, 样例输入 Data 样例输出 Data 样例说明在本样例中,DHCP 服务器一共收到了 6 个报文,处理情况如下: 第 1 个报文不是 DHCP 服务器需要处理的报文,因此不回复任何报文。 第 2 个报文中, 第 3 个报文中, 第 4 个报文中, 第 5、6 个报文中, 评测用例规模与约定对于 20% 的数据,有 N≤200,且 n≤N,且输入仅含 Discover 报文,且 t<Tmin; 对于 50% 的数据,有 N≤200,且 n≤N,且 t<Tmin,且报文的接收主机或为本机,或为 对于 70% 的数据,有 N≤1000,且 n≤N,且报文的接收主机或为本机,或为 对于 100% 的数据,有 N≤10000,且 n≤10000,主机名的长度不超过 20,且 t,Tmin,Tdefault,Tmax≤109,输入的报文格式符合题目要求,且数字不超过 109。 |
#include <iostream>
#include<algorithm>
#include<string>
#include<set>
#include<vector>
using namespace std;
string H;
set<int>WFP;
set<int>DFP;
set<int>ZY;
set<int>GQ;
int N, Tdef, Tmax, Tmin;
class DHCP {
public:
string send;
string receive;
string type;
int ip;
int overtime;
};
class IP {
public:
string state;
string name = "";
int overtime;
};
IP ipaddress[202];
void Receive(int t, DHCP dhcp)
{
if (dhcp.receive != H && dhcp.receive != "*")
if (dhcp.type != "REQ")
return;
if (dhcp.type != "DIS" && dhcp.type != "REQ")
return;
if (dhcp.receive == "*" && dhcp.type != "DIS")
return;
if (dhcp.receive == H && dhcp.type == "DIS")
return;
DHCP r_dhcp;
r_dhcp.send = H;
r_dhcp.receive = dhcp.send;
if (dhcp.type == "DIS") {
if (ZY.find(dhcp.ip) != ZY.end())
r_dhcp.ip = dhcp.ip;
else if (!WFP.empty()) {
auto it = WFP.begin();
int x = *it;
ipaddress[x].state = "DFP";
ipaddress[x].name = dhcp.send;
WFP.erase(x);
DFP.insert(x);
r_dhcp.ip = x;
}
else if (!GQ.empty()) {
auto it = GQ.begin();
int x = *it;
ipaddress[x].state = "DFP";
ipaddress[x].name = dhcp.send;
GQ.erase(x);
DFP.insert(x);
r_dhcp.ip = x;
}
else
return;
if (dhcp.overtime == 0)
r_dhcp.overtime = t + Tdef;
else {
if (dhcp.overtime - t < Tmin)
r_dhcp.overtime = Tmin + t;
else if (dhcp.overtime - t > Tmax)
r_dhcp.overtime = Tmax + t;
else
r_dhcp.overtime = dhcp.overtime;
}
ipaddress[r_dhcp.ip].overtime = r_dhcp.overtime;
r_dhcp.type = "OFR";
cout << r_dhcp.send << " " << r_dhcp.receive << " " << r_dhcp.type << " " << r_dhcp.ip << " " << r_dhcp.overtime << endl;
return;
}
if (dhcp.type == "REQ") {
if (dhcp.receive != H) {
for (auto it = DFP.begin(); it != DFP.end(); ++it) {
int x = *it;
if (ipaddress[x].name == dhcp.send) {
ipaddress[x].name = "";
ipaddress[x].state = "WFP";
ipaddress[x].overtime = 0;
DFP.erase(x);
WFP.insert(x);
break;
}
}
return;
}
if (dhcp.ip > N || dhcp.ip < 1 || ipaddress[dhcp.ip].name != dhcp.send) {
r_dhcp.type = "NAK";
r_dhcp.ip = dhcp.ip;
r_dhcp.overtime = 0;
cout << r_dhcp.send << " " << r_dhcp.receive << " " << r_dhcp.type << " " << r_dhcp.ip << " " << r_dhcp.overtime << endl;
return;
}
int x = dhcp.ip;
r_dhcp.ip = x;
ipaddress[x].state = "ZY";
DFP.erase(x);
WFP.erase(x);
GQ.erase(x);
ZY.insert(x);
if (dhcp.overtime == 0)
r_dhcp.overtime = t + Tdef;
else {
if (dhcp.overtime - t < Tmin)
r_dhcp.overtime = Tmin + t;
else if (dhcp.overtime - t > Tmax)
r_dhcp.overtime = Tmax + t;
else
r_dhcp.overtime = dhcp.overtime;
}
r_dhcp.type = "ACK";
ipaddress[r_dhcp.ip].overtime = r_dhcp.overtime;
cout << r_dhcp.send << " " << r_dhcp.receive << " " << r_dhcp.type << " " << r_dhcp.ip << " " << r_dhcp.overtime << endl;
return;
}
}
void set_time(int t) {
for (auto it = DFP.begin(); it != DFP.end();) {
int x = *it;
if (t >= ipaddress[x].overtime) {
ipaddress[x].overtime = 0;
++it;
DFP.erase(x);
WFP.insert(x);
}
else
++it;
}
for (auto it = ZY.begin(); it != ZY.end();) {
int x = *it;
if (t >= ipaddress[x].overtime) {
ipaddress[x].overtime = 0;
++it;
ZY.erase(x);
GQ.insert(x);
}
else
++it;
}
return;
}
int main() {
cin >> N >> Tdef >> Tmax >> Tmin >> H;
for (int i = 1; i <= N; ++i) {
ipaddress[i].state = "WFP";
WFP.insert(i);
}
DHCP a[202];
int t[202] = { 0 };
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> t[i]>>a[i].send>>a[i].receive>>a[i].type>>a[i].ip>>a[i].overtime;
for (int i = 1; i <= n; ++i) {
set_time(t[i]);
Receive(t[i], a[i]);
}
return 0;
}