当前位置:   article > 正文

计网实验之模拟网桥&C++读写操作_根据网桥的自学习机制,填写下表所示的网桥1和网桥2的地址转发表。

根据网桥的自学习机制,填写下表所示的网桥1和网桥2的地址转发表。

前言

本文源于计算机网络实验中一道比较有趣的题目——模拟网桥,在此记录一下网桥的原理、实现思路及代码,以及通过本次实验也让我回顾了逐渐陌生的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();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281

实验结果

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

文件数据

在这里插入图片描述在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/864103
推荐阅读
相关标签
  

闽ICP备14008679号