上机编程-简易DHCP服务器

发布时间 2023-12-11 15:06:27作者: 易先讯
题目描述

DHCP服务器的功能是为每一个MAC地址分配唯一的IP地址。现假设:分配的IP地址范围从 192.168.0.0 到 192.168.0.255 总共256个可用地址(以点分十进制表示)。请实现一个简易的DHCP服务器,功能如下:

  • 分配Request:根据输入的MAC地址分配IP地址池中的IP地址:
    • 如果对应的IP已分配并未释放,则为重复申请,直接返回对应已分配的IP地址。
    • 如果一个MAC地址已申请过并已释放,即:当前未分配IP地址,则为再申请,优先分配最近一次曾经为其分配过的IP地址,请返回此地址。
    • 按升序分配从未被分配过的IP地址;如果地址池中地址都已被分配过,则按升序分配已释放出来的IP地址;若可分配成功,则返回此IP地址。
    • 若仍然无法分配成功,则返回NA
  • 释放Release:根据输入的MAC地址释放已分配的IP地址:
    • 如果申请释放的对应的IP地址已分配,则释放此IP地址;
    • 如果申请释放的对应的IP地址不存在,则不作任何事情;
解答要求时间限制:1000ms, 内存限制:64MB
输入

首行为整数n, 表示其后输入的命令行数,范围[1,2000]。
之后每行为一条分配命令,格式为:命令=MAC地址

  • 命令只有两种:REQUEST 和 RELEASE,分别表示分配和释放;
  • MAC地址为:12个大写英文字母或数字,如:AABBCCDDEEF1
输出

1.REQUEST命令,输出分配结果(IP地址字符串或字符串NA),均为字符串形式。

注意:IP地址的各区段不设置前置 0

2.RELEASE命令,不输出任何内容。

样例

输入样例 1 复制

2
REQUEST=AABBCCDDEEF1
RELEASE=AABBCCDDEEF1

输出样例 1

192.168.0.0
提示样例 1

REQUEST=AABBCCDDEEF1 按升序分配从未使用过的IP地址,输出192.168.0.0
RELEASE=AABBCCDDEEF1 不输出



输入样例 2 复制

6
REQUEST=AABBCCDDEEF1
REQUEST=F2FBBCCDDEEF
RELEASE=AABBCCDDEEF1
RELEASE=F2FBBCCDDEEF
REQUEST=333333333333
REQUEST=F2FBBCCDDEEF

输出样例 2

192.168.0.0
192.168.0.1
192.168.0.2
192.168.0.1
提示样例 2

REQUEST=AABBCCDDEEF1 按升序分配从未使用过的IP,为192.168.0.0
REQUEST=F2FBBCCDDEEF 按升序分配从未使用过的IP,为192.168.0.1
RELEASE=AABBCCDDEEF1 释放IP 192.168.0.0。
RELEASE=F2FBBCCDDEEF 释放IP 192.168.0.1。
REQUEST=333333333333 按升序分配从未使用过的IP,为192.168.0.2
REQUEST=F2FBBCCDDEEF 该MAC地址再申请,优先分配最近一次曾经为其分配过的IP,为192.168.0.1



提示

答题要求:结果可信和过程可信同样重要,您编写的代码需要符合可信的要求(包括通用编码规范、安全编码规范和圈复杂度)。

 
 
 
##############passs##############


/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 * Description: 考生实现代码
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 * 只能import Go标准库
 */
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strconv"
    "strings"
)

type ipMac struct {
    ip         string
    mac        string
    state      string
}

type dhcpServer struct {
    ipMacs    map[string]*ipMac
    macIps    map[string]*ipMac
}

// 待实现函数,在此函数中填入答题代码
func constructor() dhcpServer {
    return dhcpServer{
        ipMacs:    make(map[string]*ipMac),
        macIps:    make(map[string]*ipMac),
    }
}

// 待实现函数,在此函数中填入答题代码。
func (d *dhcpServer) release(mac string) {
    macIp, exist := d.macIps[mac]
    if !exist {
        return
    }
    if macIp.state == "used" {
        macIp.state = "free"
    }
}

// 待实现函数,在此函数中填入答题代码。
func (d *dhcpServer) request(mac string) string {
    // mac是否存已分配ip
    if macIp, exist := d.macIps[mac]; exist {
        //重复申请,直接返回ip
        if macIp.state == "used" {
            //fmt.Println("used oldMacIp",macIp, mac)
            return macIp.ip
        }
        // 已申请并已释放,申请最近一次使用过的ip
        if macIp.state == "free" {
            macIp.state = "used"
           // fmt.Println("oldMacIp",macIp, mac)
            return macIp.ip
        }
    }
    // 优先分配没有用的
    for i:=0; i< 256; i++ {
        strLastIp := strconv.Itoa(i)
        endIp := "192.168.0." + strLastIp
        _, exist := d.ipMacs[endIp];
        //fmt.Println("i am here", endIp)
        if !exist {
            ipMacObj := &ipMac{endIp,mac, "used"}
            d.macIps[mac] = ipMacObj
            d.ipMacs[endIp] = ipMacObj
            return endIp
        }
    }
    // 全部分配,按升序分配释放的ip
    for i:=0; i< 256; i++ {
        strLastIp := strconv.Itoa(i)
        endIp := "192.168.0." + strLastIp
        //fmt.Println("i am here111", endIp)
        if d.ipMacs[endIp].state == "free" {
            delete(d.macIps, d.ipMacs[endIp].mac)
            delete(d.ipMacs, endIp)
            ipMacObj := &ipMac{endIp, mac, "used"}
            d.macIps[mac] = ipMacObj
            d.ipMacs[endIp] = ipMacObj
            return endIp
        }
    }
    return "NA"
}

func main() {
    var n int
    if _, err := fmt.Scanf("%d", &n); err != nil {
        return
    }

    miniDhcpServer := constructor()
    inputReader := bufio.NewReader(os.Stdin)
    for i := 0; i < n; i++ {
        cmd, err := getCmd(inputReader, "=")
        if err != nil || len(cmd) != 2 {
            return
        }
        if cmd[0] == "REQUEST" {
            fmt.Println(miniDhcpServer.request(cmd[1]))
        } else if cmd[0] == "RELEASE" {
            miniDhcpServer.release(cmd[1])
        }
    }
}

func getCmd(reader *bufio.Reader, sep string) ([]string, error) {
    lineBuf, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
        return nil, err
    }
    str := strings.TrimRight(lineBuf, "\r\n")
    return strings.Split(str, sep), nil
}


###################ip池#################

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 * Description: 考生实现代码
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 * 只能import Go标准库
 */
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

type ipMac struct {
    ip  uint32
    mac string
}

type ipMacs []ipMac

type dhcpServer struct {
    ipPool []uint32
    used   ipMacs
    free   ipMacs
}
// 待实现函数,在此函数中填入答题代码
func constructor() dhcpServer {
    d := dhcpServer{}
    d.ipPool = make([]uint32, 0, 256)
    d.used = make([]ipMac, 0, 256)
    d.free = make([]ipMac, 0, 256)
    for i := 0; i < 256; i++ {
        ip := uint32((192 << 24) | (168 << 16) | i)
        d.ipPool = append(d.ipPool, ip)
    }
    return d
}
// 待实现函数,在此函数中填入答题代码。
func (d *dhcpServer) request(mac string) string {
    // mac已分配还未释放直接返回对应的ip
    for _, v := range d.used {
        if v.mac == mac {
            return htoa(v.ip)
        }
    }
    // mac已申请且已释放,当再申请时优先分配
    for i, v := range d.free {
        if v.mac == mac {
            d.used = append(d.used, d.free[i])
            d.free = append(d.free[:i], d.free[i+1:]...)
            return htoa(v.ip)
        }
    }
    // 按升序分配未被分配的ip,再按已释放的地址升序分配地址
    if len(d.ipPool) == 0 {
        if len(d.free) == 0 {
            return "NA"
        }
        min := minIp(d.free)
        ip := d.free[min]
        d.used = append(d.used, ipMac{ip.ip, mac})
        d.free = append(d.free[:min], d.free[min+1:]...)
        return htoa(ip.ip)
    }
    ip := d.ipPool[0]
    d.used = append(d.used, ipMac{ip, mac})
    d.ipPool = d.ipPool[1:]
    return htoa(ip)
}
// 待实现函数,在此函数中填入答题代码。
func (d *dhcpServer) release(mac string) {
    // 若已分配则释放
    for i, v := range d.used {
        if v.mac == mac {
            d.free = append(d.free, v)
            // 从used中删除
            d.used = append(d.used[:i], d.used[i+1:]...)
            return
        }
    }
    // 若已释放则什么也不做
}
func htoa(ip uint32) string {
    return fmt.Sprintf("%d.%d.%d.%d", ip>>24, (ip>>16)&0xff, (ip>>8)&0xff, ip&0xff)
}
func minIp(ips ipMacs) int {
    if len(ips) == 1 {
        return 0
    }
    min := 0
    for i := 1; i < len(ips); i++ {
        if ips[min].ip > ips[i].ip {
            min = i
        }
    }
    return min
}

func main() {
    var n int
    if _, err := fmt.Scanf("%d", &n); err != nil {
        return
    }

    miniDhcpServer := constructor()
    inputReader := bufio.NewReader(os.Stdin)
    for i := 0; i < n; i++ {
        cmd, err := getCmd(inputReader, "=")
        if err != nil || len(cmd) != 2 {
            return
        }
        if cmd[0] == "REQUEST" {
            fmt.Println(miniDhcpServer.request(cmd[1]))
        } else if cmd[0] == "RELEASE" {
            miniDhcpServer.release(cmd[1])
        }
    }
}

func getCmd(reader *bufio.Reader, sep string) ([]string, error) {
    lineBuf, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
        return nil, err
    }
    str := strings.TrimRight(lineBuf, "\r\n")
    return strings.Split(str, sep), nil
}
View Code

 

 

 

###感受###
1.一定要懂题意
2.已申请并已释放,申请最近一次使用过的ip:结合每一个MAC地址分配唯一的IP地址,就直接看是否在map中就可以了
3.注意标点符号断句:按升序分配从未被分配过的IP地址;最后是分号,代表一个条件完了。直接考虑下一个条件即可
4.注意看描述设计结构:如果地址池中地址都已被分配过, 隐含了一个结构,ip地址池,有3中状态,空,占用,释放