C++模拟网桥转发功能

题目:写一个程序来模拟网桥功能。

模拟实现网桥的转发功能,以从文件中读取帧模拟网桥从网络中收到一帧,即从两个文件中读入一系列帧,从第一个文件中读入一帧然后从第二个文件中再读入一帧,如此下去。对每一帧,显示网桥是否会转发,及显示转发表内容。

  • 要求:Windows或Linux环境下运行,程序应在单机上运行。
  • 分析:
    1. 用程序模拟网桥功能,可以假定用两个文件分别代表两个网段上的网络帧数据。而两个文件中的数据应具有帧的特征,即有目的地址,源地址和帧内数据。程序交替读入帧的数据,就相当于网桥从网段中得到帧数据。
    2. 对于网桥来说,能否转发帧在于把接收到的帧与网桥中的转发表相比较。判断目的地址后才决定是否转发。由此可见转发的关键在于构造转发表。这里转发表可通过动态生成。

本地数据样式

注意文档中不要有多余的空格,换行。每个字符串中间是一个tab键不是8个空格键。第一次运行时,转发表可以什么内容都没有

  • 网段一

  • 网段二

  • 转发表

分析

  1. 理解好网桥的功能,代码实现并不困难(当然我的代码并不是完全符合网桥的逻辑的,是一个最简单的网桥功能实现);
  2. 这个实验让我们实现网桥的自学习和转发帧
    • 自学习:查找转发表中与收到帧的源地址有无相匹配的项目。
      -如果有,更新原有项目(简单的代码实现就更新一下时间);
      -如果没有,新增一个项目。
    • 转发帧:查找转发表中与收到帧的目的地址有无相匹配的项目。
      - 如果有,按转发表给出接口进行转发;
      - 如果没有,通过所有接口进行转发;
      - 若转发表给出的接口就是该帧进入网桥的接口,丢弃该帧。

程序流程图

代码

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <Windows.h>
#include <cstdio>
 #include <time.h>
using namespace std;

//获取string类型的本地时间
string GetSystemTimeStr()
{
	struct tm t;   //tm结构指针
	time_t now;  //声明time_t类型变量
	time(&now);      //获取系统日期和时间
	localtime_s(&t, &now);   //获取当地日期和时间
	string time;
	time.append(to_string(t.tm_year+1900));
	time.append(".");
	time.append(to_string(t.tm_mon+1));
	time.append(".");
	time.append(to_string(t.tm_mday));
	time.append("  ");
	time.append(to_string(t.tm_hour));
	time.append(":");
	time.append(to_string(t.tm_min));
	time.append(":");
	time.append(to_string(t.tm_sec));
	return time;
}

//查表,自学习并进行转发
bool forword(map<string, pair<string, string>>& forwordingTable, string frame, int flag) {
	//如果是读到文件中的第一行,返回
	if (frame == "source\tdestn\tdata") return false;
	cout << "网桥接口" << flag << "接收到帧数据" << endl;
	//网桥解析帧数据
	int firstTabIndex = frame.find_first_of("\t");
	int lastTabIndex = frame.find_last_of("\t");
	//源地址
	string source = frame.substr(0, firstTabIndex);
	//目的地址
	string destination = frame.substr(firstTabIndex + 1, lastTabIndex - firstTabIndex - 1);
	//帧内数据
	string data = frame.substr(lastTabIndex + 1, frame.size() - lastTabIndex);

	//帧离开源地址,到达网桥(按道理这语句应该在最上面,但是要用到几个变量只能放在这里)
	cout << "PC" << source << " send data to " << "PC" << destination << ": " << data << endl;
	//查转发表
	//自学习,先用源地址更新转发表
	map<string, pair<string, string>>::iterator iter = forwordingTable.find(source);
	//表中没有匹配,新增项目
	if (iter == forwordingTable.end()) {
		pair<string, string> save(to_string(flag), GetSystemTimeStr());
		forwordingTable.insert(pair<string, pair<string, string>>(source, save));
	}
	//表中有匹配,更新项目
	else forwordingTable[source].second = GetSystemTimeStr();
	//转发帧,判断转发表中是否有目的地址
	iter = forwordingTable.find(destination);
	//没有有目的地址,通过所有接口进行转发;有目的地址,按给定接口进行转发
	if (iter == forwordingTable.end()) cout << "转发表中无PC" << destination << "的信息,网桥通过所有接口进行转发" << endl;
	else if (forwordingTable[destination].first == to_string(flag)) cout << "PC" << source << "和PC" << destination << "在同一网段下,丢弃该帧数据" << endl;
	else cout << "从接口" << flag << "处进行转发" << endl;
	//帧离开网桥网桥,到达目的地址
	cout << "PC" << destination << " receive data from " << source << ": " << data << endl << endl;
	return true;
}

int main() {
	//读取两网段和转发表文件
	ifstream segment1File("segment1.txt");
	if (!segment1File.is_open()) {
		cout << "segmeng1文件打开失败!" << endl;
		return 1;
	}
	ifstream segment2File("segment2.txt");
	if (!segment2File.is_open()) {
		cout << "segmeng2文件打开失败!" << endl;
		return 1;
	}
	ifstream forwordingTableFileRead("forwordingTable.txt");
	if (!forwordingTableFileRead.is_open()) {
		cout << "forwordingTable文件打开失败!" << endl;
		return 1;
	}

	//用地图存起来转发表
	map<string, pair<string,string>> forwordingTable;
	string row;
	while (getline(forwordingTableFileRead, row))
	{
		//忽略第一行标题
		if (row == "PC\tsegment\ttime") continue;
		//找到制表符位置
		int firstTabIndex = row.find_first_of('\t');
		int lastTabIndex = row.find_last_of("\t");
		//获取map的key和value,插入map
		string key = row.substr(0, firstTabIndex);
		string value = row.substr(firstTabIndex +1, lastTabIndex - firstTabIndex - 1);
		string time = row.substr(lastTabIndex + 1, row.size() - lastTabIndex);
		pair <string, string> save(value, time);
		forwordingTable.insert(pair<string, pair<string,string>>(key, save));
	}

	//帧数据
	string frame;
	//交替读入标志
	int flag = 1;
	//网桥开始工作
	while (!segment1File.eof() || !segment2File.eof()) {
		if (flag == 1) {
			if (!segment1File.eof()) {
				//读网段一中的一行
				getline(segment1File, frame);
				if(!forword(forwordingTable, frame, flag)) continue;
			}
			//交替
			flag = 2;
		}
		if (flag == 2) {
			if (!segment2File.eof()) {
				//读网段二中的一行
				getline(segment2File, frame);
				if (!forword(forwordingTable, frame, flag)) continue;
			}
			//交替
			flag = 1;
		}
	}

	//更新转发表到本地
	ofstream forwordingTableFileWrite("forwordingTable.txt");
	if (!forwordingTableFileWrite.is_open()) {
		cout << "forwordingTable文件打开失败!" << endl;
		return 1;
	}
	forwordingTableFileWrite << "PC\tsegment\ttime" << endl;
	for (auto mapIndex : forwordingTable) {
		forwordingTableFileWrite << mapIndex.first << "\t" << mapIndex.second.first << "\t" << mapIndex.second.second<<endl;
	}

	//完成工作,关闭文件
	segment1File.close();
	segment2File.close();
	forwordingTableFileRead.close();
	forwordingTableFileWrite.close();
	return 0;
}

结果截图

  • 第一次转发表中没有任何信息

  • 第二次转发表中已经有了全部信息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是用 C++ 一个简单的程序模拟网桥的基本功能: ```c++ #include <iostream> #include <unordered_map> #include <vector> using namespace std; class Bridge { private: int bridge_id; unordered_map<string, int> mac_table; vector<pair<int, string>> port_states; public: Bridge(int id) { bridge_id = id; } void receive_frame(int port, const string& src_mac, const string& dst_mac, const string& data) { // Learn source MAC address mac_table[src_mac] = port; // Check destination MAC address if (mac_table.count(dst_mac) > 0) { int dst_port = mac_table[dst_mac]; if (dst_port != port) { // Forward frame to destination port forward_frame(dst_port, src_mac, dst_mac, data); } } else { // Flood frame to all ports except source port for (auto& p : port_states) { if (p.first != port) { forward_frame(p.first, src_mac, dst_mac, data); } } } } void forward_frame(int port, const string& src_mac, const string& dst_mac, const string& data) { cout << "Bridge " << bridge_id << " forwarding frame to port " << port << ": src_mac=" << src_mac << ", dst_mac=" << dst_mac << ", data=" << data << endl; port_states[port].second = "forwarding"; } void add_port(int port_id, const string& state) { port_states.push_back(make_pair(port_id, state)); } void remove_port(int port_id) { for (auto it = port_states.begin(); it != port_states.end(); ++it) { if (it->first == port_id) { port_states.erase(it); break; } } } }; // Example usage: int main() { Bridge bridge1(1); bridge1.add_port(1, "forwarding"); bridge1.add_port(2, "forwarding"); string src_mac1 = "00:11:22:33:44:55"; string dst_mac1 = "aa:bb:cc:dd:ee:ff"; string data1 = "Hello world!"; bridge1.receive_frame(1, src_mac1, dst_mac1, data1); string src_mac2 = "aa:bb:cc:dd:ee:ff"; string dst_mac2 = "00:11:22:33:44:55"; string data2 = "Goodbye!"; bridge1.receive_frame(2, src_mac2, dst_mac2, data2); return 0; } ``` 这个程序定义了一个 `Bridge` 类来表示一个网桥,它可以添加/移除端口并接收/转发网桥维护一个 MAC 地址表来学习每个源 MAC 地址对应的端口,并根据目的 MAC 地址将转发到正确的端口。如果目的 MAC 地址没有在表找到,则将泛洪到所有端口(除源端口外)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值