Python实现一个简单的主机-路由器结构(计算机网络)

说明

本系统模拟实现了一个路由器与两个主机节点。该路由器将接收原始以太网帧,并像真正的路由器一样处理它们:将它们转发到正确的传出接口,处理以太网帧,处理 IPv4 分组,处理 ARP分组,处理 ICMP 分组,创建新帧等。这个路由器将模拟实现路由器处理主机节点发送的以太网帧的操作。

运行展示

源代码

import queue
import threading
import time
import socket
import uuid# 十进制转二进制
def dec_to_bin_str(num):return str(bin(num))[2:]# 二进制转十进制
def bin_to_dec_str(binary):return str(int(binary, 2))# IP地址转二进制
def ipv4_to_binary(ipv4):binary_list = ['{0:08b}'.format(int(num)) for num in ipv4.split('.')]return ''.join(binary_list)# 二进制地址转点分十进制
def binary_to_ipv4(binary_str):if len(binary_str) != 32:return "Invalid binary string"segments = [binary_str[i:i+8] for i in range(0, 32, 8)]ipv4_address = ".".join(str(int(segment, 2)) for segment in segments)return ipv4_address# 验证校验和
def validate_ip_checksum(data):# 初始化总合为0total = 0# 每16位为单位进行遍历for i in range(0, len(data), 16):word = int(data[i:i + 16], 2)total += word# 按位与操作和右移操作,在总和的低16位中和高16位中分别加上结果total = (total & 0xffff) + (total >> 16)# 再次按位与操作和右移操作,对结果再次进行相加total = (total + (total >> 16)) & 0xffff# 将总和与0xffff进行异或运算,并将结果转换为16位二进制数checksum = '{:016b}'.format(total ^ 0xffff)return checksum# IP数据报的格式(IPv4格式)
class IPv4Message:def __init__(self, version, header_length, service, total_length, identification, flags, fragment_offset, ttl, protocol, checksum, source_address, destination_address, data):self.version = version                              # 版本self.header_length = header_length                  # 首部长度self.service = service                              # 区分服务self.total_length = total_length                    # 总长度self.identification = identification                # 标识self.flags = flags                                  # 标志self.fragment_offset = fragment_offset              # 片偏移self.ttl = ttl                                      # 生存时间self.protocol = protocol                            # 协议self.checksum = checksum                            # 校验和self.source_address = source_address                # 源地址self.destination_address = destination_address      # 目的地址self.data = data                                    # 数据# 以太网MAC帧的格式
class MACMessage:def __init__(self, mac_destination, mac_source, protocol_type, data):self.mac_destination = mac_destinationself.mac_source = mac_sourceself.protocol_type = protocol_type    # 为IPv4self.data = data# ICMP差错报文格式
class ICMPError:def __init__(self, message_type, checksum, data):self.type = message_type   # 1-主机不可达self.checksum = checksumself.data = data# ICMP回送请求或回答报文格式
class ICMPMessage:def __init__(self, message_type, checksum, data):self.type = message_type    # 类型字段,8-请求,0-回答self.checksum = checksumself.data = data# ARP广播格式
class ARPBroadcast:def __init__(self):self.mac = "FF:FF:FF:FF:FF:FF"# 获取本机IP与本机MAC
my_ip = socket.gethostbyname(socket.gethostname())
my_mac = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) for elements in range(0, 2 * 6, 2)][::-1])# ARP表
arp_table = {my_ip: my_mac, '172.26.213.121': '00:11:22:33:44:55', '172.26.213.64': '00:aa:bb:cc:dd:ee'}# 路由表
route_table = {my_ip: 'direct', '172.26.213.121': 'direct', '0.0.0.0': '172.26.213.64'}# 路由器类
class Router:def __init__(self):self.ip = my_ipself.mac = my_macself.arp_table = arp_tableself.routing_table = route_tableself.frame_queue = queue.Queue()def route(self):while True:# 拆开frame获取IP数据报frame_message = self.frame_queue.get()if frame_message == "":continueip_message = frame_message.split("@")[-1]ip_header = ip_message[0:160]# 计算校验和checksum = ip_header[80:96]rest = ip_header[-64:]print("路由器:计算的校验和为:" + checksum)ip_message_t = ip_header[0:80]ip_message_t += "0000000000000000"ip_message_t += restif not checksum == validate_ip_checksum(ip_message_t):print("路由器:校验和验证失败")# 发送一个ICMP响应报文print("路由器:发送一个ICMP响应报文告知主机")continueprint("路由器:校验和验证成功")# 验证TTL合法性ttl = int(bin_to_dec_str(ip_header[64:72]))if ttl <= 0:print("TTL值不合法")# 发送一个ICMP响应报文print("路由器:发送一个ICMP响应报文告知主机")continueelse:# 自减ttl -= 1# 拆解IP首部ip_source = binary_to_ipv4((ip_message[0:160])[-64:-32])ip_destination = binary_to_ipv4((ip_message[0:160])[-32:])print("路由器:源IP:" + ip_source + ",目的IP:" + ip_destination)# 转发的framenew_frame_message = ""# 根据路由表查目的IP地址for ip, move in route_table.items():if ip == ip_destination:# 修改IP头部,源地址改变但目的地址不变if move == "direct":print("路由器:目标可直达,直接转发")elif move == "upper":print("路由器:目标为本身,交付上层")breakelse:ip_header = ip_header[0:-32]ip_header += ipv4_to_binary(route_table["0.0.0.0"])print("路由器:新的IP数据报已生成,下一跳IP地址为:" + route_table["0.0.0.0"])# 根据ARP表获取下一跳MAC,封装成帧,转发mac_source = self.macfor m_ip, mac in arp_table.items():if ip_header[-32:] == ipv4_to_binary(m_ip):mac_destination = macnew_frame_message += mac_destination + "@" + mac_source + "@IPv4@" + ip_messageprint("路由器:路由器已转发,下一跳MAC为:", mac)# 主机节点类
class Host:def __init__(self, ip, mac):self.ip = ipself.mac = mac# 获取目的MAC地址(广播ARP请求分组并接收ARP响应分组)def get_dest_mac(self, dest_ip):print("主机:正在进行ARP广播")dest_mac = "FF:FF:FF:FF:FF:FF"for ip, mac in arp_table.items():if ip == dest_ip:dest_mac = my_macprint("主机:目标MAC已获取" + dest_mac)return dest_mac# 初始化校验和def make_checksum(self, ip_header, dest_ip):ip_header += "0000000000000000"ip_header += ipv4_to_binary(self.ip) + ipv4_to_binary(dest_ip)data = ip_headertotal = 0for i in range(0, len(data), 16):word = int(data[i:i + 16], 2)total += wordtotal = (total & 0xffff) + (total >> 16)total = (total + (total >> 16)) & 0xffffchecksum = '{:016b}'.format(total ^ 0xffff)print("主机:生成的校验和为:" + checksum)return checksum# 发送数据帧def send_frame(self, dest_ip, data):# 组装IP数据报ip_header = "0100"                                      # 版本号为4ip_header += "0101"                                     # 首部长度20Bip_header += "00000000"                                 # 区分服务ip_header += dec_to_bin_str(len(data) + 20).zfill(16)   # 总长度ip_header += "0000000000000000"                         # 标识ip_header += "000"                                      # 标志ip_header += "0000000000000"                            # 片偏移ip_header += "00000000"                                 # 生存时间ip_header += "00000000"                                 # 协议ip_header += self.make_checksum(ip_header, dest_ip)     # 校验和ip_header += ipv4_to_binary(self.ip)                    # 源地址ip_header += ipv4_to_binary(dest_ip)                    # 目的地址ip_message = ip_header + data                           # 组装成IP数据报# 组装数据帧frame_head = self.get_dest_mac(dest_ip)frame_head += "@" + self.mac + "@IPv4@"frame_message = frame_head + ip_message# 发送给路由器print("主机:数据帧发送完毕")my_router.frame_queue.put(frame_message)# 路由器与主机节点
my_router = Router()
my_host1 = Host("172.26.213.121", "00:11:22:33:44:55")
my_host2 = Host("172.26.213.122", "00:11:22:33:44:55")# 打开线程
router_thread = threading.Thread(target=my_router.route)
router_thread.start()# 标志位
flag = True# 打印本机IP与MAC,即路由器IP、MAC
print("本机IP:" + my_ip + " 本机MAC:" + my_mac)# 轮询输入
while True:message = input("主机:请输入要发送的消息:")if message == "exit":print("主机已关闭")breakif message == "shift":flag = not flagcontinueif flag:my_host1.send_frame(my_ip, message)else:my_host2.send_frame("172.26.21.12", message)time.sleep(1)# 释放资源,关闭线程
router_thread.join()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

沉浸式感受旧时光,VR全景让游客都爱上老街区打卡地

近年来&#xff0c;随着城市建设的推进&#xff0c;很多老建筑以及周边的道路都发生了很大的变化&#xff0c;为了让更多的游客可以领略城市发展的进程以及旧时的人文风情&#xff0c;很多城市都会通过实地场景拍摄制作VR全景&#xff0c;将老街区、老建筑的真实场景进行虚拟再…

新型masked勒索病毒袭击工控行业

2019年10月9号总部设在荷兰海牙的欧洲刑警组织与国际刑警组织共同发布报告《2019互联网有组织犯罪威胁评估》&#xff0c;报告指出数据已成为网络犯罪分子的主机攻击目标&#xff0c;勒索软件仍是网络安全最大威胁&#xff0c;全球各界需要加强合作&#xff0c;联合打击网络犯罪…

【Vue3】路由的query参数和params参数

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Python数据分析-pandas3

1.pandas的作用&#xff1a; numpy能够帮助我们处理数值&#xff0c;但是pandas除了处理数值之外&#xff08;基于numpy&#xff09;&#xff0c;还能够帮助我们处理其他类型的数据。 2.pandas之Series创建&#xff1a; 3.pandas之Series切片和索引 4.缺失值处理 5.常用的统计…

【C语言刷题】——初识位操作符

【C语言刷题】——初识位操作符 位操作符介绍题一、 不创建临时变量&#xff08;第三个变量&#xff09;&#xff0c;实现两个数的交换&#xff08;1&#xff09;法一&#xff08;2&#xff09;法二 题二、 求一个数存储在内存中的二进制中“一”的个数&#xff08;1&#xff0…

phpcms上传漏洞

原始漏洞 漏洞原理&#xff1a;我们上传一个zip的压缩包&#xff0c;它会解压然后删除其中不是.jpg .gig .png的文件 function check_dir($dir)&#xff1a;这是一个PHP函数的定义&#xff0c;它接受一个参数 $dir&#xff0c;代表要检查的目录路径。 $handle opendir($dir)…

【React】Vite创建React+TS项目

前提条件 有node环境&#xff0c;且node版本>18.0.0 创建项目 npm create vitelatest1.起项目名 2.选择框架 3.选择语言 TypeScript SWC 是指 Vite 使用 SWC&#xff08;Speedy Web Compiler&#xff09;作为 TypeScript 的编译器。 SWC 是一个针对 JavaScript 和 Ty…

客服销冠偷偷用的提效神器!无广很实用

近期发现我的同事每天上班必登录的一款软件——客服宝聊天助手&#xff0c;用过才发现&#xff1a;真客服办公的提效神器&#xff01;感兴趣的小伙伴请往下看~一、客服宝的简介&#xff1a;客服宝聊天助手&#xff0c;是一款跨平台快捷回复工具。自带多种功能&#xff0c;有效帮…

Python接口自动化测试post请求和get请求,获取请求返回值

引言 我们在做python接口自动化测试时&#xff0c;接口的请求方法有get,post等&#xff1b;get和post请求传参&#xff0c;和获取接口响应数据的方法&#xff1b; 请求接口为Post时&#xff0c;传参方法 我们在使用python中requests库做接口测试时&#xff0c;在做post接口测试…

C语言练习题【复试准备】

1、BoBo教KiKi字符常量或字符变量表示的字符在内存中以ASCII码形式存储。BoBo出了一个问题给KiKi&#xff0c;转换以下ASCII码为对应字符并输出他们。 //73,32,99,97,110,32,100,111,32,105,116,33 int main() {int arr[] {73,32,99,97,110,32,100,111,32,105,116,33};int i …

备战2024年汉字小达人活动:历年区级样题练习和解析(续)

今天我们继续来看汉字小达人活动的区级样题。区级样题是中文自修杂志社&#xff08;主办方&#xff09;发布的试题&#xff0c;主要是给学校老师选拔参考使用的&#xff0c;据了解&#xff0c;很多学校老师是直接用这个样卷在学校组织选拔&#xff0c;选拔成绩突出的同学报给主…

Pytorch学习 day10(L1Loss、MSELoss、交叉熵Loss、反向传播)

Loss loss的作用如下&#xff1a; 计算实际输出和真实值之间的差距为我们更新模型提供一定的依据&#xff08;反向传播&#xff09; L1Loss 绝对值损失函数&#xff1a;在每一个batch_size内&#xff0c;求每个输入x和标签y的差的绝对值&#xff0c;最后返回他们平均值 M…

Kafka配置SASL_PLAINTEXT权限。常用操作命令,创建用户,topic授权

查看已经创建的topic ./bin/kafka-topics.sh --bootstrap-server localhost:9092 --list 创建topic 创建分区和副本数为1的topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --topic acltest --partitions 1 --replication-factor 1 创建kafka用户 …

HTML静态网页成品作业(HTML+CSS+JS)——迪士尼公主介绍(6个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代码…

基于单片机的酒精浓度测试仪

摘 要 现如今&#xff0c;人们对生活的态度和生活方式变得不同,&#xff0c;不仅私家车成为了人们最普遍的交通工具&#xff0c;大多数人都有自己的私家车,而且人们对酒精的消耗量也越来越大&#xff0c;这些就导致酒后驾车行为越来越普遍&#xff0c;酒后驾车意外越来越频繁&…

【深度学习笔记】10_10 束搜索beam-search

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 10.10 束搜索 上一节介绍了如何训练输入和输出均为不定长序列的编码器—解码器。本节我们介绍如何使用编码器—解码器来预测不定长的序…

3dmax2020模型显示黑白不稳定---模大狮模型网

如果在3ds Max 2020中显示的模型出现黑白不稳定的情况&#xff0c;可能有几个常见原因和解决方法&#xff1a; 显卡驱动问题&#xff1a; 首先检查你的显卡驱动程序是否是最新版本。过时或不兼容的显卡驱动可能导致显示问题。建议更新到最新的显卡驱动程序&#xff0c;并确保其…

YOLOv9(3):YOLOv9损失(Loss)计算

1. 写在前面 YOLOv9的Loss计算与YOLOv8如出一辙&#xff0c;仅存在略微的差异。多说一句&#xff0c;数据的预处理和导入方式都是一样的。因此如果你已经对YOLOv8了解的比较透彻&#xff0c;那么对于YOLOv9你也只是需要多关注网络结构就可以。 YOLOv9本身也是Anchor-Free的&a…

编译esp32s3的ncnn,并运行mnist 手写数字识别

东哥科技&#xff0c;专注科技研发&#xff0c;wx交流&#xff1a;dg_i688 我的项目代码 https://github.com/cdmstrong/ncnn_on_esp32s3 下载ncnn git clone https://github.com/Tencent/ncnn.git安装idf 环境 这里直接按官网的可执行文件来就好了&#xff0c;直接安装完…

[mysql必备面试题]-mysql索引(B+ Tree )

一 B Tree 原理 1. 数据结构 B Tree 指的是 Balance Tree&#xff0c;也就是平衡树。平衡树是一颗查找树&#xff0c;并且所有叶子节点位于同一层。 B Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现&#xff0c;它具有 B Tree 的平衡性&#xff0c;并且通过顺序访问指针…