基于Simpy/Python的通信网络仿真工具(二):多主机、端口互联实现数据包转发与交换机仿真

基于Simpy的通信网络仿真工具(二):多主机、端口互联实现数据包转发与交换机仿真

基于Simpy/Python的通信网络仿真工具(一):数据包生成,转发和接收

Host模块

在主机(Host)中具有数据包生成器(Pg)和接收器(Ps),实现代码如下

class Host(object):
    """ 
    功能: 实现数据包产生、发出和接收
    参数
    -------
        address : 地址
        dist : 时隙大小
        dst_adrees : 目的地址列表
        size_list : 包大小列表
        interval : 包产生间隔时间
        rec_arrivals: 包接收间隔时间
        absolute_arrivals: 包接收时间
        debug: 日志打印
    """
    def __init__(self, env, address, dst_address, interval=None, rec_arrivals=False, absolute_arrivals=False, debug=False) -> None:
        self.env = env
        self.address = address
        self.pg = PacketGenerator(env, src=address, dst_list=dst_address, interval=interval)
        self.ps = PacketSink(
            env, host=address, rec_arrivals=rec_arrivals, absolute_arrivals=absolute_arrivals, debug=debug)

    # 设置包的大小信息
    def setPktSize(self, pkt_size_list):
        """ 
        pkt_size_list : size列表
        """
        self.size_list = pkt_size_list
    # 连接(out)目标交换机
    def setLink(self, target):
        self.pg.out = target.in_port

Port模块

一个端口(Port)需要同时具备接收、转发和发出功能,代码如下

class Port(object):
    """ 
    功能: 接收和转发全功能端口,实现端口的接收和转发
    参数
    ------
        env: 运行环境
        port_id: 端口的id
        trans_list: 内部端口的连接列表, A_in --> B_out, C_out
        table: 转发规则表, src-dst : port_out
        valid_time: 流表有效时间
        send_rate: out端口的传输速率
        queue_limit: 队列最大长度
        is_limit: 是否丢包
        debug: 输出执行信息
    """
    def __init__(self, env, port_id, trans_list, table=None, valid_time=None,
                 send_rate=0, queue_limit=None, is_limit=True, debug=False) -> None:
        self.env = env
        self.switch_id = None
        self.port_id = port_id 
        self.queue = []   # 端口队列记录
        self.drop = []    # 端口丢包记录
        self.in_port = SwitchPortIn(env=env, trans_list=trans_list, valid_time=valid_time,
                                                    table=table, debug=debug)
        self.out_port = SwitchPortOut(env=env, address=None, rate=send_rate, qlimit=queue_limit,
                                                      limit_bytes=is_limit, debug=debug)

    # 设置转发表(判断包应该转发到哪个port的out)
    def setTable(self, table):
        self.in_port.table = table

    # 设置out端口的连接对象
    def setOutObj(self, out):
        self.out_port.out = out

    # 设置in端口的连接对象
    def setTransPort(self, target_list):
        for i in range(len(target_list)):
            self.in_port.out[i] = target_list[i].out_port

    # 获取out端口的队列
    def getQueue(self):
        return self.out_port.queue

    # 输出out端口的丢包情况
    def getOutDrop(self):
        return self.out_port.out_drop

    def __repr__(self):
        return "switch_address :{}, port_id :{}".format(self.switch_id, self.port_id)

三主机、端口传输仿真

在数据包数据包生成,转发和接收和基础上,本部分根据以下拓扑实现,数据转发仿真
在这里插入图片描述

# Port仿真, 三port, 三host
import simpy
import random

UNTIL_TIME = 10 # 仿真时间
def constArrival():
    return 0.8   # time interval
def getTransList1():
    return [2, 3]
def getTransList2():
    return [1, 3]
def getTransList3():
    return [1, 2]
# 生成转发规则
def getTable1():
    return {"H1-H2": 2, "H1-H3": 3}
def getTable2():
    return {"H2-H1": 1, "H2-H3": 3}
def getTable3():
    return {"H3-H1": 1, "H3-H2": 2}

if __name__=='__main__':
    port_rate = 1200.0
    env = simpy.Environment()  # Create the SimPy environment
    h1 = Host(env, "H1", dst_address=["H2", "H3"], interval=constArrival, rec_arrivals=True, debug=False)
    h2 = Host(env, "H2", dst_address=["H1", "H3"], interval=constArrival, rec_arrivals=True, debug=False)
    h3 = Host(env, "H3", dst_address=["H1", "H2"], interval=constArrival, rec_arrivals=True, debug=False)
    
    pt1 = Port(env=env, port_id = 1, trans_list=getTransList1(), table=getTable1(), 
            send_rate=port_rate, queue_limit=1001, debug=False)
    pt2 = Port(env=env, port_id = 2, trans_list=getTransList2(), table=getTable2(),
            send_rate=port_rate, queue_limit=1001, debug=False)  # rate 是波特率
    pt3 = Port(env=env, port_id = 3, trans_list=getTransList3(), table=getTable3(),
            send_rate=port_rate, queue_limit=1001, debug=False)  # rate 是波特率
    h1.pg.out = pt1.in_port
    pt1.setTransPort(target_list=[pt2, pt3])
    pt2.setOutObj(h2.ps)
    
    h2.pg.out = pt2.in_port
    pt2.setTransPort(target_list=[pt1, pt3])
    pt1.setOutObj(h1.ps)

    h3.pg.out = pt3.in_port
    pt3.setTransPort(target_list=[pt1, pt2])
    pt3.setOutObj(h3.ps)

    env.run(until=UNTIL_TIME)
    print("received: {}, queuing: {}, out dropped {}, sent {}".format(
        h1.ps.packets_rec + h2.ps.packets_rec + h3.ps.packets_rec, 
        len(pt1.out_port.queue)+ len(pt2.out_port.queue) + len(pt3.out_port.queue),
        len(pt1.getOutDrop())+ len(pt2.getOutDrop()) + len(pt3.getOutDrop()),
        h1.pg.packets_sent + h2.pg.packets_sent + h3.pg.packets_sent))

    print("h1 received ids: {}".format(h1.ps.arrivals_id))
    print("h2 received ids: {}".format(h2.ps.arrivals_id))
    print("h3 received ids: {}".format(h3.ps.arrivals_id))
    print("pt1 queue ids : {}".format([pkt.id for pkt in pt1.out_port.queue]))
    print("pt2 queue ids: {}".format([pkt.id for pkt in pt2.out_port.queue]))
    print("pt3 queue ids: {}".format([pkt.id for pkt in pt3.out_port.queue]))
    print("pt1 out drop ids: {}".format([pkt.id for pkt in pt1.out_port.out_drop]))
    print("pt2 out drop ids: {}".format([pkt.id for pkt in pt2.out_port.out_drop]))
    print("pt3 out drop ids: {}".format([pkt.id for pkt in pt3.out_port.out_drop]))

结果如下:

received: 42, queuing: 26, out dropped 4, sent 72
h1 received ids: ['H2-H1-1', 'H3-H1-1', 'H2-H1-3', 'H3-H1-3', 'H2-H1-5', 'H3-H1-5', 'H2-H1-7', 'H3-H1-7', 'H2-H1-9', 'H3-H1-9', 'H2-H1-11', 'H3-H1-11', 'H2-H1-13', 'H3-H1-13', 'H2-H1-15']
h2 received ids: ['H1-H2-1', 'H3-H2-2', 'H1-H2-3', 'H3-H2-4', 'H1-H2-5', 'H3-H2-6', 'H1-H2-7', 'H3-H2-8', 'H1-H2-9', 'H3-H2-10', 'H1-H2-11', 'H3-H2-12', 'H1-H2-13', 'H3-H2-14', 'H1-H2-15']
h3 received ids: ['H1-H3-2', 'H2-H3-2', 'H1-H3-4', 'H2-H3-4', 'H1-H3-6', 'H2-H3-6', 'H1-H3-8', 'H2-H3-8', 'H1-H3-10', 'H2-H3-10', 'H1-H3-12', 'H2-H3-12']
pt1 queue ids : ['H3-H1-15', 'H2-H1-17', 'H3-H1-17', 'H2-H1-19', 'H3-H1-19', 'H2-H1-21', 'H3-H1-21', 'H2-H1-23', 'H3-H1-23'] 
pt2 queue ids: ['H3-H2-16', 'H1-H2-17', 'H3-H2-18', 'H1-H2-19', 'H3-H2-20', 'H1-H2-21', 'H3-H2-22', 'H1-H2-23', 'H3-H2-24']  
pt3 queue ids: ['H1-H3-14', 'H2-H3-14', 'H1-H3-16', 'H2-H3-16', 'H1-H3-18', 'H1-H3-20', 'H1-H3-22', 'H2-H3-22']
pt1 out drop ids: []
pt2 out drop ids: []
pt3 out drop ids: ['H2-H3-18', 'H2-H3-20', 'H1-H3-24', 'H2-H3-24']

通过设置数据包产生间隔时间,影响网络的拥塞程度。

def constArrival():
    return 0.6   # time interval

运行结果

received: 44, queuing: 37, out dropped 15, sent 96
h1 received ids: ['H2-H1-1', 'H3-H1-1', 'H2-H1-3', 'H3-H1-3', 'H2-H1-5', 'H3-H1-5', 'H2-H1-7', 'H3-H1-7', 'H2-H1-9', 'H3-H1-9', 'H2-H1-11', 'H3-H1-11', 'H2-H1-13', 'H3-H1-13', 'H2-H1-15']
h2 received ids: ['H1-H2-1', 'H3-H2-2', 'H1-H2-3', 'H3-H2-4', 'H1-H2-5', 'H3-H2-6', 'H1-H2-7', 'H3-H2-8', 'H1-H2-9', 'H3-H2-10', 'H1-H2-11', 'H3-H2-12', 'H1-H2-13', 'H3-H2-14']
h3 received ids: ['H1-H3-2', 'H2-H3-2', 'H1-H3-4', 'H2-H3-4', 'H1-H3-6', 'H2-H3-6', 'H1-H3-8', 'H2-H3-8', 'H1-H3-10', 'H2-H3-10', 'H1-H3-12', 'H2-H3-12', 'H1-H3-14', 'H2-H3-14', 'H1-H3-16']
pt1 queue ids : ['H3-H1-15', 'H2-H1-17', 'H3-H1-17', 'H2-H1-19', 'H2-H1-21', 'H3-H1-21', 'H2-H1-23', 'H3-H1-23', 'H2-H1-25', 'H3-H1-25', 'H2-H1-29', 'H3-H1-29']
pt2 queue ids: ['H1-H2-15', 'H3-H2-16', 'H1-H2-17', 'H3-H2-18', 'H1-H2-19', 'H1-H2-21', 'H3-H2-24', 'H3-H2-26', 'H1-H2-27', 'H3-H2-28', 'H1-H2-29', 'H3-H2-30', 'H1-H2-31', 'H3-H2-32']
pt3 queue ids: ['H2-H3-16', 'H1-H3-18', 'H1-H3-20', 'H2-H3-20', 'H1-H3-22', 'H1-H3-24', 'H1-H3-26', 'H1-H3-28', 'H2-H3-28', 'H1-H3-30', 'H2-H3-30']
pt1 out drop ids: ['H3-H1-19', 'H2-H1-27', 'H3-H1-27', 'H2-H1-31', 'H3-H1-31']
pt2 out drop ids: ['H3-H2-20', 'H3-H2-22', 'H1-H2-23', 'H1-H2-25']
pt3 out drop ids: ['H2-H3-18', 'H2-H3-22', 'H2-H3-24', 'H2-H3-26', 'H1-H3-32', 'H2-H3-32']

对比结果可知,间隔越小,网络丢包率越高,队列排队程度越长。

交换机仿真

在三端口的拓扑中,三端口合并即为一个交换机,如下图所示
在这里插入图片描述
整合了端口的交换机代码如下,主要功能包括初始端口,连接端口对应的设备

class Switch(object):
    def __init__(self, env, address, port_num, send_rate, queue_limit, valid_time=None, ctrler=None, debug=False):
        self.address = address # 交换机的地址
        self.port_num_list = [i for i in range(port_num)]  # 端口编号列表
        self.port_list = [None for _ in range(port_num)]  # 端口列表
        # 生成每个端口
        for port_i in range(port_num):
            trans_list = self.port_num_list.copy()  # 对象数组采用copy
            trans_list.remove(port_i)  # 生成port_i 对应的 转发端口列表
            self.port_list[port_i] = Port(
                env, switch_addr = self.address, port_id = port_i, trans_list=trans_list, valid_time=valid_time, table=None, send_rate=send_rate, queue_limit=queue_limit, debug=debug)

        # 连接交换机内部的端口
        for port in self.port_list:
            trans_list = self.port_list.copy()
            trans_list.remove(port)  # 生成port 对应的 转发端口
            port.setTransPort(target_list=trans_list)  # 连接转发端口

    # 设置转发表
    def setTables(self, tables_list):
        for i in range(len(tables_list)):
            self.port_list[i].setTable(tables_list[i])

    # 设置连接对象
    def setLink(self, link_list, port_list):
        """ 
        link_list : 连接对象(Port or Host)
        port_list : 目标对象的端口编号,连接主机时为空
         """
        # print([host.address for host in link_list])
        # print(self.port_list)
        for i in range(len(link_list)):
            if type(link_list[i]) is Host:
                # 设置(out)连接对象
                self.port_list[i].setOutObj(link_list[i].ps)
                # 设置(in)连接对象
                link_list[i].setLink(self.port_list[i])
            else:
                # 设置(out)连接对象, 交换机与交换机之间均为 in-->out
                self.port_list[i].setOutObj(link_list[i].port_list[port_list[i]].in_port)
        
    def __repr__(self):
        return "address :{}".format(self.address)

转发测试代码如下

def constArrival():
    return 0.8   # time interval
def getTable1():
    return {"H1-H2": 1, "H1-H3": 2} # 交换机的端口编号 从0开始
def getTable2():
    return {"H2-H1": 0, "H2-H3": 2}
def getTable3():
    return {"H3-H1": 0, "H3-H2": 1}

if __name__=='__main__':
    port_rate = 1200.0
    env = simpy.Environment()  # Create the SimPy environment
    h1 = Host(env, address = "H1", dst_address=["H2", "H3"], interval=constArrival, rec_arrivals=True, debug=False)
    h2 = Host(env, address = "H2", dst_address=["H1", "H3"], interval=constArrival, rec_arrivals=True, debug=False)
    h3 = Host(env, address = "H3", dst_address=["H1", "H2"], interval=constArrival, rec_arrivals=True, debug=False)
    
    swicth = Switch(env=env, address = 'S1', port_num=3, send_rate=port_rate, queue_limit=1001, debug=False)
    link_list = [h1, h2, h3]
    swicth.setLink(link_list=link_list, port_list=[]) 
    swicth.setTables([getTable1(), getTable2(), getTable3()])
    env.run(until=UNTIL_TIME)
    print("received: {}, queuing: {}, out dropped {}, sent {}".format(
        h1.ps.packets_rec + h2.ps.packets_rec + h3.ps.packets_rec, 
        len(swicth.port_list[0].out_port.queue)+ len(swicth.port_list[1].out_port.queue) + len(swicth.port_list[2].out_port.queue),
        len(swicth.port_list[0].getOutDrop())+ len(swicth.port_list[1].getOutDrop()) + len(swicth.port_list[2].getOutDrop()),
        h1.pg.packets_sent + h2.pg.packets_sent + h3.pg.packets_sent))

    print("h1 received ids: {}".format(h1.ps.arrivals_id))
    print("h2 received ids: {}".format(h2.ps.arrivals_id))
    print("h3 received ids: {}".format(h3.ps.arrivals_id))
    print("pt1 queue ids : {}".format([pkt.id for pkt in swicth.port_list[0].out_port.queue]))
    print("pt2 queue ids: {}".format([pkt.id for pkt in swicth.port_list[1].out_port.queue]))
    print("pt3 queue ids: {}".format([pkt.id for pkt in swicth.port_list[2].out_port.queue]))
    print("pt1 out drop ids: {}".format([pkt.id for pkt in swicth.port_list[0].out_port.out_drop]))
    print("pt2 out drop ids: {}".format([pkt.id for pkt in swicth.port_list[1].out_port.out_drop]))
    print("pt3 out drop ids: {}".format([pkt.id for pkt in swicth.port_list[2].out_port.out_drop])) 

结果如下:

received: 35, queuing: 34, out dropped 3, sent 72
h1 received ids: ['H2-H1-1', 'H3-H1-1', 'H2-H1-3', 'H3-H1-3', 'H2-H1-5', 'H3-H1-5', 'H2-H1-7', 'H3-H1-7', 'H2-H1-9', 'H3-H1-9', 'H2-H1-11']
h2 received ids: ['H1-H2-1', 'H3-H2-2', 'H1-H2-3', 'H3-H2-4', 'H1-H2-5', 'H3-H2-6', 'H1-H2-7', 'H3-H2-8', 'H1-H2-9', 'H3-H2-10', 'H1-H2-11', 'H3-H2-12']
h3 received ids: ['H1-H3-2', 'H2-H3-2', 'H1-H3-4', 'H2-H3-4', 'H1-H3-6', 'H2-H3-6', 'H1-H3-8', 'H2-H3-8', 'H1-H3-10', 'H2-H3-10', 'H1-H3-12', 'H2-H3-12']
pt1 queue ids : ['H3-H1-11', 'H2-H1-13', 'H3-H1-13', 'H2-H1-15', 'H3-H1-15', 'H2-H1-17', 'H3-H1-17', 'H2-H1-19', 'H3-H1-19', 'H2-H1-21', 'H3-H1-21']
pt2 queue ids: ['H1-H2-13', 'H3-H2-14', 'H1-H2-15', 'H3-H2-16', 'H1-H2-17', 'H3-H2-18', 'H1-H2-19', 'H3-H2-20', 'H3-H2-22', 'H1-H2-23', 'H3-H2-24']
pt3 queue ids: ['H1-H3-14', 'H2-H3-14', 'H1-H3-16', 'H2-H3-16', 'H1-H3-18', 'H2-H3-18', 'H1-H3-20', 'H2-H3-20', 'H1-H3-22', 'H2-H3-22', 'H1-H3-24', 'H2-H3-24']
pt1 out drop ids: ['H2-H1-23', 'H3-H1-23']
pt2 out drop ids: ['H1-H2-21']
pt3 out drop ids: []

比较三端口和交换机仿真可知,交换机主要是将端口的初始化和连接关系进行整合封装,提高效率。
然而,目前交换机的转发规则时固定的,如需要动态改变转发策略,则需要控制器的加入,并动态下发转发流表。

欢迎通过企鹅(488128665)进行交流!
以上仿真内容代码下载:基于Simpy/Python的通信网络仿真工具

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值