欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【计算机网络】模拟分组交换网络的时延、丢包(Java语言描述)

程序员文章站 2022-07-10 18:14:40
...

ttrans & tprop

ttrans

这是传输时延,是将所有分组的比特推向链路(即传输,或者说发射)所需要的时间。

tprop

这是传播时延,是从链路的起点到路由器B传播所需要的时间。

区别

打个比方:
【背景】高速公路收费站口A到B上有一个速度一样的、含有很多车的车队……
【模拟】一个车相当于一个比特,一个车队相当于一个分组,收费站相当于路由器,高速路相当于传输比特的物理媒体……
【情景分析】
过了A收费站后,从A到B,这段走在高速路上的时间,相当于传播时延。
而汽车们到了收费站B处需要排队等待(假设只有一个收费窗口),排队和放行需要时间,排队等待放行的时间是传输时延。

设计思路

我们既然要让网络拥塞导致缓存区满丢包,那就要让ttrans > tprop。不妨设传输时延为2s,传播时间为1s,使得现象更明显些。

数据结构

模拟缓存区要使用FIFO队列,为使用方便我选择了自己手写一个链式队列。

定义结点

为简便起见,使用单链表式的链队列比较好,所以需要一个单链表结点:

private static class Node<T> {
    T value;
    Node<T> next;
    Node(T value) {
        this.value = value;
    }
}

定义队列

队列设置一下size,因为需要与MAX_SIZE做比较。
要有指向队首和队尾的两个指针,head和rear。

需要isFull()、isEmpty()这两个判队列满和队列空的函数。

enQueue()是入队操作,要判满;deQueue()是出队操作,要判空。

其余不讲,数据结构的内容而已……

private static class Queue<T> {
    private static final int MAX_SIZE = 5;
    int size;
    Node<T> head, rear;
    synchronized void enQueue(T value) throws QueueFullException {
        if (isFull()) {
            throw new QueueFullException();
        }
        Node<T> newNode = new Node<>(value);
        if (isEmpty()) {
            rear = head = newNode;
        } else {
            rear.next = newNode;
            rear = newNode;
        }
        ++size;
    }
    synchronized T deQueue() throws QueueEmptyException {
        if (isEmpty()) {
            throw new QueueEmptyException();
        }
        Node<T> removeNode = head;
        head = head.next;
        --size;
        return removeNode.value;
    }
    private boolean isEmpty() {
        return size == 0;
    }
    private boolean isFull() {
        return size == MAX_SIZE;
    }
}

为了同步就加上synchronized吧 orz

异常

要注意的是我们为上面的异常情况设置了两个异常类:

出队队空异常

private static class QueueEmptyException extends Exception { }

入队队满异常

private static class QueueFullException extends Exception { }

线程

需要两种线程,一种是入队线程,另一种是出队线程。

为了能sleep(),进而控制节奏,就允许它们继承Thread吧,Runnable反而显得不便。

入队线程

private static class enQueueThread extends Thread {
    int counter;
    enQueueThread(int counter) {
        this.counter = counter;
    }
    @Override
    public void run() {
        try {
            queue.enQueue(counter);
        } catch (QueueFullException e) {
            System.out.println("发生丢包");
        }
    }
}

出现异常就提示丢包。

出队线程

private static class deQueueThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("第" + queue.deQueue() + "个包被发送");
        } catch (QueueEmptyException e) {
            System.out.println("没有可发送的包");
        }
    }
}

出现异常就提示没有可发的包。

完整代码

package org.self.test.net;

public class PackageLostTest {

    private static Queue<Integer> queue = new Queue<>();

    private static class QueueEmptyException extends Exception { }

    private static class QueueFullException extends Exception { }

    private static class Node<T> {
        T value;
        Node<T> next;
        Node(T value) {
            this.value = value;
        }
    }

    private static class Queue<T> {
        private static final int MAX_SIZE = 5;
        int size;
        Node<T> head, rear;
        synchronized void enQueue(T value) throws QueueFullException {
            if (isFull()) {
                throw new QueueFullException();
            }
            Node<T> newNode = new Node<>(value);
            if (isEmpty()) {
                rear = head = newNode;
            } else {
                rear.next = newNode;
                rear = newNode;
            }
            ++size;
        }
        synchronized T deQueue() throws QueueEmptyException {
            if (isEmpty()) {
                throw new QueueEmptyException();
            }
            Node<T> removeNode = head;
            head = head.next;
            --size;
            return removeNode.value;
        }
        private boolean isEmpty() {
            return size == 0;
        }
        private boolean isFull() {
            return size == MAX_SIZE;
        }
    }

    private static class enQueueThread extends Thread {
        int counter;
        enQueueThread(int counter) {
            this.counter = counter;
        }
        @Override
        public void run() {
            try {
                queue.enQueue(counter);
            } catch (QueueFullException e) {
                System.out.println("发生丢包");
            }
        }
    }

    private static class deQueueThread extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("第" + queue.deQueue() + "个包被发送");
            } catch (QueueEmptyException e) {
                System.out.println("没有可发送的包");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int counter = 0;
        while (true) {
            enQueueThread thread1 = new enQueueThread(++counter);
            deQueueThread thread2 = new deQueueThread();
            thread1.start();
            thread2.start();
            Thread.sleep(1000);
            enQueueThread thread3 = new enQueueThread(++counter);
            thread3.start();
            Thread.sleep(1000);
        }
    }

}

测试丢包的结果

只截取运行到34个包的结果:

1个包被发送
第2个包被发送
第3个包被发送
第4个包被发送
第5个包被发送
发生丢包
第6个包被发送
发生丢包
第7个包被发送
发生丢包
第8个包被发送
发生丢包
第9个包被发送
发生丢包
第10个包被发送
发生丢包
第12个包被发送
发生丢包
第14个包被发送
发生丢包
第16个包被发送
发生丢包
第18个包被发送
发生丢包
第20个包被发送
发生丢包
第22个包被发送
发生丢包
第24个包被发送
发生丢包
第26个包被发送
发生丢包
第28个包被发送
发生丢包
第30个包被发送
发生丢包
第32个包被发送
发生丢包
第34个包被发送
……

测试网络空闲的情况

public static void main(String[] args) throws InterruptedException {
    int counter = 0;
    while (true) {
        enQueueThread thread1 = new enQueueThread(++counter);
        deQueueThread thread2 = new deQueueThread();
        thread1.start();
        thread2.start();
        Thread.sleep(1000);
        deQueueThread thread3 = new deQueueThread();
        thread3.start();
        Thread.sleep(1000);
    }
}

只截取运行到7个包的结果:

1个包被发送
没有可发送的包
第2个包被发送
没有可发送的包
第3个包被发送
没有可发送的包
第4个包被发送
没有可发送的包
第5个包被发送
没有可发送的包
第6个包被发送
没有可发送的包
第7个包被发送
没有可发送的包

总结

ttrans 和 tprop 之间还是有不小差别的,这里我们用一种模拟的方式来直观地验证这二者的差别,希望能使读者更清楚这二者的差别。

代码使用Java编写,原创不易,感谢支持orz