进程与端口的系统设计题

发布时间 2023-12-13 15:01:50作者: 易先讯
#####题目
1. FlowStatsSystem

在一台计算机上运行着多个网络程序的进程,每个进程可以绑定多个端口,每个端口同一时刻只能被绑定在一个进程上,每个端口在绑定成功后可以接收网络报文。
请设计一个流量统计的简易系统,实现下面接口:
FlowStatsSystem() – 系统初始化。
bindport(int pid,int port) - 绑定一个端口port到进程pid上,如果此port已经被绑定,则绑定失败并且返回false;否则绑定成功,并返回true。
unbindPort(int port) - 解除端口port和进程的绑定关系。如果此端口已被绑定,则解除绑定,已接收的报文不清零,并返回true;否则直接返回false。
recvPacket(int port,int packetLen) -端口port上收到一段长度为packetLen的报文,
如果端口port没有被绑定在任何一个进程上,则直接返回0,报文丢弃。
如果端口port已绑定在某个进程上,则这个进程接收的[报文总长度]累加packetLen,然后返回[报文总长度]。
statPacket(int topNum) - 统计收到报文总长度最大的topNum个进程,并按如下规则返回这些进程pid的列表:
对于未接收过报文的进程,不统计。
优先按进程接收的[报文总长度]降序;若总长度相同,再按进程pid升序。
若符合条件的进程数不足topNum,按实际数量返回;若无符合条件的,返回空列表[]。

输入
每行表示一个函数调用,初始化函数仅首行调用一次,累计函数调用不超过100次。
1<=port<=65535,1<=pid<=100000,1<=packetLen<=100000,1<=topNum<=5
输出
答题时按照函数/方法原型中的要求(含返回值)进行实现,输出由框架完成(其中首行固定输出null)


思路:

注意到pid对应报文长度不会被清除。所以题目简化为 pid2Len,port2pid两个映射。 其中pid2Len为只增加的
关键问题就是排序

package main

import (
	"fmt"
	"sort"
)

type PidSystem struct {
	pid       int
	packetLen int
}

type FlowStatsSystem struct {
	ZERO    int
	portMap map[int]int // port => pid
	pidMap  map[int]*PidSystem // pid => pidSystem
}

func NewFlowStatsSystem() *FlowStatsSystem {
	return &FlowStatsSystem{
		ZERO:    0,
		portMap: make(map[int]int),
		pidMap:  make(map[int]*PidSystem),
	}
}

func (f *FlowStatsSystem) bindPort(pid int, port int) bool {
	if _, ok := f.portMap[port]; ok {
		return false
	} else {
		f.portMap[port] = pid
		return true
	}
}

func (f *FlowStatsSystem) unbindPort(port int) bool {
	if _, ok := f.portMap[port]; ok {
		delete(f.portMap, port)
		return true
	}
	return false
}

func (f *FlowStatsSystem) recvPacket(port int, packetLen int) int {
	if _, ok := f.portMap[port]; !ok {
		return f.ZERO
	}
	pid := f.portMap[port]
	pidSystem, ok := f.pidMap[pid]
	if !ok {
		pidSystem = &PidSystem{pid: pid, packetLen: f.ZERO}
		f.pidMap[pid] = pidSystem
	}
	pidSystem.packetLen += packetLen
	return pidSystem.packetLen
}

func (f *FlowStatsSystem) statPacket(topNum int) []int {
	var filterPid []*PidSystem
	for _, v := range f.pidMap {
		if v.packetLen > 0 {
			filterPid = append(filterPid, v)
		}
	}
	if len(filterPid) == f.ZERO {
		return []int{}
	}
	sort.Slice(filterPid, func(i, j int) bool {
		if filterPid[i].packetLen == filterPid[j].packetLen {
			return filterPid[i].pid < filterPid[j].pid
		}
		return filterPid[i].packetLen > filterPid[j].packetLen
	})
	res := make([]int, len(filterPid))
	for i, v := range filterPid {
		res[i] = v.pid
	}
	if len(res) > topNum {
		return res[:topNum]
	} else {
		return res
	}
}

func main() {
	flowStatsSystem := NewFlowStatsSystem()
	flowStatsSystem.bindPort(23215, 443)
	flowStatsSystem.bindPort(23215, 443)
	flowStatsSystem.bindPort(23215, 3306)
	flowStatsSystem.bindPort(23216, 3306)
	flowStatsSystem.bindPort(23216, 80)
	flowStatsSystem.recvPacket(3306, 100)
	flowStatsSystem.recvPacket(443, 200)
	flowStatsSystem.recvPacket(80, 300)
	flowStatsSystem.unbindPort(443)
	ints := flowStatsSystem.statPacket(2)
	fmt.Println(ints)
}




#### 感受
1. 设计能力薄弱,只能设计到portMap(port => pid),但是没办法pidMap(pid => pidSystem)中使用 map结构体
2. 经典排序Top问题, 先排序,然后取top(如果len小于top,取全部)// 默写100次
3. 1->n; n->1 主键都在n里面 n->m 需要新增一张表