赞
踩
本文源于计算机网络实验中一道比较有趣的题目——模拟网桥,在此记录一下网桥的原理、实现思路及代码,以及通过本次实验也让我回顾了逐渐陌生的C++(读写文件操作)。
写一个程序来模拟网桥功能。
模拟实现网桥的转发功能,以从文件中读取帧模拟网桥从网络中收到一帧,即从两个文件中读入一系列帧,从第一个文件中读入一帧然后从第二个文件中再读入一帧,如此下去。对每一帧,显示网桥是否会转发,及显示转发表内容。
要求: Windows或Linux环境下运行,程序应在单机上运行。
分析: 用程序模拟网桥功能,可以假定用两个文件分别代表两个网段上的网络帧数据。而两个文件中的数据应具有帧的特征,即有目的地址,源地址和帧内数据。程序交替读入帧的数据,就相当于网桥从网段中得到帧数据。
对于网桥来说,能否转发帧在于把接收到的帧与网桥中的转发表相比较。判断目的地址后才决定是否转发。由此可见转发的关键在于构造转发表。这里转发表可通过动态生成。
题意相当于模拟下图的网桥转发的过程,一个网桥连接两个网段的主机,通过转发表进行转发。
网桥转发原理: 包括两个步骤:自学习和转发帧。首先,网桥对两个端口发来的帧解析出源主机和目的主机的地址,在转发表中查找是否有源主机的端口信息,若找不到,网桥则在转发表中添加源主机的信息(源地址、进入的接口和时间)(由于是模拟实验,因此没有考虑时间这个要素)。【自学习】 之后,在转发表中查找是否有目的主机的端口信息,若找不到,则向除接收端口以外的端口转发帧,若找到,则需要判断目的主机和源主机是否处在端口的同一侧,若是,则丢弃帧,无需转发,否则,向转发表中指定的端口转发帧。【转发帧】
图示:
说明: 此图来自于其他文章,当时感觉画得很好,直接拿来使用。
由于没有及时记录文章链接,无法注明图片来源,如果图片作者看到可以留言一下,抱歉!感谢!
1、生成数据:利用随机数分配网段的主机,再生成随机的帧数据,并写入到两个文件中,分别代表在来两个端口的数据
2、核心算法:首先一次读取文件1一行数据,并解析成主机地址和发送的数据的信息。之后,先进入自学习阶段,查询转发表中是否有源主机,没有则更新转发表;接着判断是否需要转发帧,查询转发表中是否有目的主机的信息,找到目的主机则还行对比源主机和目的主机所属的网段,决定丢弃帧还是转发帧。到这里完成了从端口1的一帧数据的处理,端口2的处理同理。
代码中用到的数据结构:
①Data:定义了帧的结构(包含源主机名、目的主机名、传送的数据)
②Host:定义了假设的各网段上主机的分别情况(包含主机id,主机名,所连端口号等,并包含了初始化的方法等)
③forwarding_table:定义了转发表的结构(包含主机名和所属的端口号)
代码源于博主自己编写的,本人能力有限,若有问题,欢迎指教!
#include <iostream> #include <fstream> #include <ctime> #include <random> #include <stdio.h> #include <windows.h> using namespace std; #define file1 "bridge1.txt" #define file2 "bridge2.txt" #define hostNum 8 //定义8台主机 #define portNum 2 //定义端口 #define messageNum 10 //每个文件发送的帧数 int hostNumSeg1; //网段1的主机数 int hostNumSeg2; //网段2的主机数 struct Host { //定义主机结构 int *id; //主机id(0-∞) char *name; //主机名称(字母A-Z) int *port; //主机所接网桥端口(1,2) int *segment1; //网段1的主机 int *segment2; //网段2的主机 void init() { //给主机随机分配端口 //printf("连接到网桥的主机有%d台\n", hostNum); id = new int[hostNum]; port = new int[hostNum]; name = new char[hostNum]; srand(unsigned(time(NULL))); for (int i = 0; i < hostNum; ++i) { id[i] = i; name[i] = 'A' + i; port[i] = rand() % 2 + 1; } //画出网桥中主机分布状态 int *list; list = new int[hostNum]; //查询两个端口的主机分布,端口为1的主机索引放在数组左侧,端口为2的主机索引放在数组右侧 int pstart=-1, pend=hostNum; //数组指针 for (int i = 0; i < hostNum; ++i) { //printf("主机%c连接在端口%d...\n", name[i], port[i]); if (port[i] == 1) list[++pstart] = i; else list[--pend] = i; } hostNumSeg1 = pstart + 1; hostNumSeg2 = hostNum - pend; segment1 = new int[hostNumSeg1]; //网段1的主机数为pstart+1 segment2 = new int[hostNumSeg2]; //网段2的主机数为hostNum-pend //printf("连接端口1的主机有:"); for (int i = 0; i <= pstart; ++i) { //printf("%c ", name[list[i]]); segment1[i] = list[i]; } //printf("\n"); //printf("连接端口2的主机有:"); for (int i = hostNum - 1; i >= pend; --i) { printf("%c ", name[list[i]]); segment2[hostNum - 1 - i] = list[i]; } //printf("\n\n"); //画图 printf("主机和网桥的分布图如下:\n"); for (int i = 0; i <= pstart; ++i) printf("%c ", name[list[i]]); printf(" 1◤◥2 "); for (int i = hostNum - 1; i >= pend; --i) printf("%c ", name[list[i]]); printf("\n"); delete[]list; } void drop() { delete[]id; delete[]name; delete[]port; } }; struct Data { 定义帧数据结构 char sourceHost; //源主机 char positionHost; //目的主机 char data[11]; //假设每一帧数据长度为10,数据随机生成 }; void fileWrite(Host host) // { Data data; //fstream fileExit; //fileExit.open(file1, ios::in); //if (fileExit) { // printf("目录下有同名文件存在!删除文件...\n"); // remove(file1); //文件存在,则删除原文件 //} printf("\n网段1:"); for (int i = 0; i < hostNumSeg1; ++i) printf("%c ", host.name[host.segment1[i]]); printf("\n"); printf("\n网段2:"); for (int i = 0; i < hostNumSeg2; ++i) printf("%c ", host.name[host.segment2[i]]); printf("\n\n写入网段1的帧数据...\n"); ofstream file; //声明一个输出流文件对象 file.open(file1); //向网段1文件写入数据 for(int i=0; i < messageNum; i++) { //网段1文件file1中生成10帧的数据 data.sourceHost = host.name[host.segment1[rand() % hostNumSeg1]]; //随机取一台网段1的主机作为源主机 printf("源主机:%c\t", data.sourceHost); while (true) { data.positionHost = host.name[rand() % hostNum]; //目的主机可以是两个网段的任意一台(除了自己) if (data.positionHost == data.sourceHost) continue; else break; } printf("目的主机:%c\t", data.positionHost); for (int i = 0; i < 10; ++i) data.data[i] = '0'+(rand() % 2); //数据为0、1比特流(字符型) printf("数据:"); for (int i = 0; i < 10; ++i)printf("%c",data.data[i]); printf("\n"); file << data.sourceHost << " "; //数据写入文件 for (int i = 0; i < 10; ++i) file << data.data[i]; file << " " << data.positionHost << '\n'; } file.close(); //关闭io数据流 printf("\n"); printf("写入网段2的帧数据...\n"); file.open(file2); //向网段1文件写入数据 for (int i = 0; i < messageNum; i++) { //网段2文件file2中生成10帧的数据 int host_idx = rand() % hostNumSeg2; data.sourceHost = host.name[host.segment2[host_idx]]; //随机取一台网段1的主机作为源主机 printf("源主机:%c\t", data.sourceHost); while (true) { data.positionHost = host.name[rand() % hostNum]; //目的主机可以是两个网段的任意一台(除了自己) if (data.positionHost == data.sourceHost) continue; else break; } printf("目的主机:%c\t", data.positionHost); for (int i = 0; i < 10; ++i) data.data[i] = '0' + (rand() % 2); //数据为0、1比特流(字符型) printf("数据:"); for (int i = 0; i < 10; ++i)printf("%c", data.data[i]); printf("\n"); file << data.sourceHost << " "; //数据写入文件 for (int i = 0; i < 10; ++i) file << data.data[i]; file << " " << data.positionHost << '\n'; } file.close(); //关闭io数据流 printf("\n"); } struct forwarding_table { //转发表数据结构 char *hostName; //主机名 int *port; //端口号 void init() { hostName = new char[hostNum]; port = new int[hostNum]; } void drop() { delete[]hostName; delete[]port; } }; void sendData(Host host) { forwarding_table table; //建立一个转发表 table.init(); //转发表初始化 int table_idx = 0; //转发表主机数 ifstream file_1, file_2; file_1.open(file1); //打开网段1帧数据文件 file_2.open(file2); //打开网段1帧数据文件 Data data; for (int i = 0; i < messageNum; ++i) //交替读取帧数据,转发数据,更新转发表 { //读取网段1文件========================================================= char message[15]; if (!file_1.eof()) { file_1.getline(message, 20); //读取一帧的数据 printf("读取帧数据信息:%s", message); } printf("\n"); //解析message data.sourceHost = message[0]; for (int i = 0; i < 10; ++i) data.data[i] = message[i + 2]; data.data[10] = '\0'; data.positionHost = message[13]; //printf("帧数据解析结果:主机%c向主机%c发送数据%s\n", data.sourceHost, data.positionHost, data.data); //=========自学习阶段,查找转发表中是否有源主机的信息=========== bool NotFound = true; for (int i = 0; i < table_idx; ++i) //核心算法 { if (data.sourceHost == table.hostName[i]) { //在转发表中找到源主机 NotFound = false; break; } } if (NotFound) { //转发表中没有源主机信息 table.hostName[table_idx] = data.sourceHost; table.port[table_idx++] = 1; //记录来自端口1的主机 printf("向转发表中添加主机%c...\n",data.sourceHost); } //=========转发帧判断========= NotFound = true; NotFound = true; for (int i = 0; i < table_idx; ++i) //核心算法 { if (data.positionHost == table.hostName[i]) { //在转发表中找到目的主机 NotFound = false; if (table.port[i] == 1) printf("目的主机%c和源主机%c在同一个网段,帧数据不转发...\n", data.positionHost, data.sourceHost); else printf("来自端口1的主机%c发送的数据通过端口2进行转发...\n", data.sourceHost); break; } } if (NotFound == true) { //在转发表中找不到主机,广播并更新转发表 printf("找不到目的主机%c,向所有端口广播数据...\n",data.positionHost); } Sleep(500); //读取网段2文件========================================================= if (!file_2.eof()) { file_2.getline(message, 20); //读取一帧的数据 printf("读取帧数据信息:%s", message); } printf("\n"); //解析message data.sourceHost = message[0]; for (int i = 0; i < 10; ++i) data.data[i] = message[i + 2]; data.data[10] = '\0'; data.positionHost = message[13]; //printf("帧数据解析结果:主机%c向主机%c发送数据%s\n", data.sourceHost, data.positionHost, data.data); //=========自学习阶段,查找转发表中是否有源主机的信息=========== NotFound = true; for (int i = 0; i < table_idx; ++i) //核心算法 { if (data.sourceHost == table.hostName[i]) { //在转发表中找到源主机 NotFound = false; break; } } if (NotFound) { //转发表中没有源主机信息 table.hostName[table_idx] = data.sourceHost; table.port[table_idx++] = 1; //记录来自端口1的主机 printf("向转发表中添加主机%c...\n",data.sourceHost); } //=========转发帧判断========= NotFound = true; for (int i = 0; i < table_idx; ++i) //核心算法 { if (data.positionHost == table.hostName[i]) { //在转发表中找到目的主机 NotFound = false; if (table.port[i] == 2) printf("目的主机%c和源主机%c在同一个网段,帧数据不转发...\n", data.positionHost, data.sourceHost); else printf("来自端口2的主机%c发送的数据通过端口1进行转发...\n", data.sourceHost); break; } } if (NotFound == true) { //在转发表中找不到主机,广播并更新转发表 printf("找不到目的主机%c,向所有端口广播数据...\n",data.positionHost); } Sleep(500); //打印转发表 //printf("当前转发表:\n"); //for (int i = 0; i < table_idx; ++i) { // printf("主机%c\t端口%d\n", table.hostName[i], table.port[i]); //} printf("\n"); } //打印转发表 printf("\n当前转发表:\n"); for (int i = 0; i < table_idx; ++i) { printf("主机%c\t端口%d\n", table.hostName[i], table.port[i]); } printf("\n"); file_1.close(); file_2.close(); table.drop(); } int main() { Host host; host.init(); fileWrite(host); sendData(host); host.drop(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。