模拟总线型以太网数据帧发送过程

本文通过C++实现了一个模拟两台主机在总线型以太网上使用CSMA/CD协议和二进制指数退避算法发送数据帧的程序。主机在检测到总线空闲后发送数据,并在冲突发生时执行随机延迟重发。程序展示了数据冲突的随机性以及如何通过调整重传策略避免持续冲突。
摘要由CSDN通过智能技术生成

2、要求

(1)在一台计算机上模拟总线型以太网数据帧发送过程,总线上连接的计算机个数为2个,支持CSMA\CD协议(二进制指数退避算法)

(2)用两个线程a和b模拟以太网上的两台主机。用一个双字类型变量Bus模拟总线。

(3)两个子线程向总线发送自己的数据。数据用该线程的线程号进行模拟,发送数据用线程号的Bus的“或”进行模拟。每台主机须向总线上成功发送5次数据,如果其中某次数据发送失败,则该线程结束。

  1. 相关知识

以太网的核心技术是随机争用型介质访问方法,即带有冲突检测的载波侦听多路访问(CSMA/CD)方法。

1.以太网的帧的发送流程

(1)载波侦听过程。以太网中每个节点利用总线发送数据,总线是每个结点共享的公共传输介质。所以结点在发送一个帧前,必须侦听总线是否空闲,由于以太网的数据采用曼彻斯特编码方式,所以可以通过判断总线电平是否跳变来确定总线是否空闲。若总线空闲,就可启动发送,否则继续侦听。

(2)冲突检测。在数据发送过程中,可能会产生冲突(冲突是指总线上同时出现两个或两个以上的发送信号,他们叠加后的信号波形与任何发送结点输出的信号波形不相同。因为可能有多个主机都在侦听总线,当它们侦听到总线空闲时,都会往总线上发送数据)。所以在发送数据的过程中,也应该进行冲突检测,只要发现冲突就应该停止发送数据。

(2)随机延迟后重发。在检测到冲突、停止发送后,结点进行随机延迟重发。若重发16次后还没成功,则宣告发送失败,取消该帧的发送。随机延迟的计算方法一般采用截至二进制指数后退算法。该算法可表示为:t=2k*R*a ,其中t为结点重新发送需要的后退延迟时间,a为冲突窗口值(冲突窗口为总线最大长度和电磁波在介质中的传播速度比值的2倍),R为随机数,k的取值为k=min(n,10),n为该帧已发送的次数。

  1. 实现原理

原理:

发送方:

某站点需要发送数据帧,首先侦听信道:

  1. 如果信道空闲,站点立即发送数据帧;
  2. 在发送数据帧过程中,边发送边冲突检测;
  3. 如果信道忙,继续侦听直到信道变为空闲,再发送数据帧

如果再发送过程中检测到冲突,则:

  1. 立即停止发送该数据帧;
  2. 给总线上发送一串阻塞加强信号,告诉其他站点总线发生冲突;
  3. 等待一段随机时间(利用二进制指数退避算法),再重新争用总线,重复上面步骤,并重发该数据帧。

接收方:

  1. 检查是否发生冲突,若发生冲突,则丢弃该帧;若没有冲突,进入下一步。
  2. 检查该帧的目的地址是否可以接收该帧,若可以接收,则进入下一步。
  3. 检查CRC校验和LLC数据长度。若都正确,接收该帧,否则丢弃。

5、程序代码

#include <iostream>
#include <thread>
#include <stdlib.h>
#include <windows.h>
#include <math.h>
#include <mutex>
#define T 5 //在这里,以毫秒为单位,故延迟窗口为5ms
using namespace std;
int BUS;
int randnum[128];//随机数库
int randnumi;//随机数库访问变量
mutex myout;
class Host
{
public:
    char id;              //主机ID
    int centcount;        //发送次数
    int collisionCounter; //发送失败最对次数
    int successcount;     //成功计数器
    int data;
    Host(char idIN, int a, int b, int sc)
    {
        id = idIN;
        centcount = a;
        collisionCounter = b;
        successcount = sc;
        data = randnum[randnumi++];
        myout.lock();
        cout << "主机" << id << "已就绪." << endl;
        myout.unlock();
    }
    int csmacd(int a,int randn)
    {
        int k = min(a, 10);
        int r = randn % k;
        return (pow(2, r) - 1) * T;
    }

    void send()
    {
        int cCounter = 0; //失败次数计数器
        while (true)
        {
            if (successcount >= centcount)
                break;
            if (BUS == 0)
            {
                Sleep((int)(T*(randnum[randnumi++]%5) )); //模拟占用总线的时间.
                BUS = BUS | data;
                Sleep((int)(T*(randnum[randnumi++]%5) ));
                if (BUS == data)
                {
                    successcount++;
                    myout.lock();
                    cout << id << " send " << data << " success,总 " << successcount << " 次成功. ///" << endl;
                    myout.unlock();
                    cCounter = 0;
                    data=randnum[randnumi++];
                    BUS = 0;
                }
                else
                {
                    cCounter++;
                    myout.lock();
                    cout << id << " send " << data << " collision,第" <<cCounter<<" 次失败."<< endl;
                    myout.unlock();
                    BUS = 0;
                    Sleep(csmacd(cCounter,randnum[randnumi++]));

                    if (cCounter >= collisionCounter)
                    {
                        myout.lock();
                        cout << id << " send" << data << " failure" << endl;
                        myout.unlock();
                        data=randnum[randnumi];
                        cCounter = 0;
                        BUS = 0;
                    }
                }
            }
            else
            {
                Sleep(randnum[randnumi++] % 10);
            }
        }
    }
};
void a()
{
    Host host('A', 5, 16, 0); //第二个参数为修改的需要成功的次数
    host.send();
}
void b()
{
    Host host('B', 5, 16, 0);
    host.send();
}
int main()
{   srand(time(0));
    for(int i=0;i<128;i++){
        randnum[i]=rand();
    }
    randnumi=0;
    thread A(a);
    thread B(b);
    A.join();
    B.join();
    return 0;
}

6、运行结果与分析

 

       经过多次测试, 可以观察到,数据的冲突具有随机性, 并且由于在一开始两个发送方都征用信道,造成大概率的信道堵塞, 多次发送失败, 当发送失败次数多了后, 就有一方有较大的随即延迟, 此时另一方即可迅速发完. 最后当两个节点发送数据基本不再冲突.

       我的报告中对发送方式的修改: 修改为在一个线程中连续发送五次成功后才退出线程. (基本原理与创建线程发送无异).

一、课程设计目的与意义是在数据链路层数据进行传输与交换的基本单位。构造对于理解网络协议的概念、协议执行过程以及网络问题处理的一般方法具有重要的意义。本次课程设计的目的是应用数据链路层与介质访问控制层的知识,根据数据链路层的基本原理,通过构造一个具体的Ethernet,从而深入理解网络协议的基本概念与网络问题处理的一般方法。二、课程设计要求编写程序,根据给出的原始数据,组装一个IEEE802.3格式的,(默认的输入文件为二进制原始数据(文件名分别为li和lzy))。1) 要求程序为命令行程序。比如,可执行文件各为framer.exe,则命令行形式如下:framer inputfile outpurfile其中,inputfile为原始数据文件,outpurfile为输出结果。2) 输出:对应input1和input2的结果分别为output1和output2。3) 开发环境:硬件环境:PC微机软件环境:Windows 2000 Microsoft Visual C++ 6.0三、结构分析1.的介绍术语“”来源于串行线路上的通信。其中,发送者在发送数据的前后各添加特殊的字符,使它们成为一个。Ethernet从某种程序上可以被看作是机器这间的数据链路层连接。首先我们来认识一下Ethernet结构,Ethernet V2.0规范和IEEE802.3标准中的Ethernet结构有一些差别,这里我们按802.3标准的结构进行讨论,图一给出了Ethernet结构图。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值