广州大学计算机网络实验报告五《网络程序设计》2023年

news2025/1/17 23:17:51

广州大学学生实验报告

开课学院及实验室:      

学院

年级、专业、班

姓名

学号

实验课程名称

计算机网络实验

成绩

实验项目名称

网络程序设计

指导老师

(1)实验目的

通过程序模拟网桥的工作原理以及检验和的计算,或者编写数据包的监听与分析程序,使学生加深对网络知识的理解。

(2)实验环境

操作系统windows xp、以太网;

(3)实验内容

  1. 写一个程序来模拟网桥功能。

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

要求:Windows或Linux环境下运行,程序应在单机上运行。

分析:用程序模拟网桥功能,可以假定用两个文件分别代表两个网段上的网络帧数据。而两个文件中的数据应具有帧的特征,即有目的地址,源地址和帧内数据。程序交替读入帧的数据,就相当于网桥从网段中得到帧数据。

对于网桥来说,能否转发帧在于把接收到的帧与网桥中的转发表相比较。判断目的地址后才决定是否转发。由此可见转发的关键在于构造转发表。这里转发表可通过动态生成。

实现步骤:

  1. 先通过代码编写,随机生成两个文件,文件中包含随机生成的帧,其包括帧的目的地址、源地址、帧内数据;
  2. 通过代码编写,写出模拟网桥功能的程序。

模拟网桥需要具备的功能:

1、网桥转发表是动态的,初始时为空表;

2、通过读取待转发的帧中的源地址,判断转发表中是否已存在该地址,若不存在,则记录该地址及其对应的端口;

3、判断待转发的帧中的目的地址是否存在于转发表中,若不存在,则通过广播进行转发,转发后结束帧转发工作;

4、判断源地址和目的地址是否处于同一网段,若存在,则丢弃该帧,不进行转发操作;否则,在该表中查找该目的地址的端口并进行帧的转发。

程序流程图:

模拟的网络拓扑图:

程序部分运行结果:

程序代码1:该段代码用于生成需要用到的相关数据,即两个存储帧的文件。

import random

import pandas

# 地址

addrlist = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']

# 生成的第一个帧数据文件

frame_data1 = []

n = random.randint(10, 15)  # 帧文件的数据行数为:5~10之间的随机数

for i in range(n):

    addr = random.sample(addrlist, 2)  # 随机取两个样本,分别作为目的地址target和源地址source

    addr.append(random.randint(1, 200))  # 插入一个1~200的随机数作为帧内数据

    frame_data1.append(addr)  # 将数据插入到frame_data1中

frame_data1 = pandas.DataFrame(frame_data1, columns=['target', 'source', 'data'])  # 创建一个表格数据结构,存储数据

frame_data1.to_csv('frame_data1.csv', index=False)  # 将表格的数据结构做成一个表格文件

print(frame_data1)  # 打印表格文件

# 生成第二个帧数据文件

frame_data2 = []

n = random.randint(10, 15)

for i in range(n):

    addr = random.sample(addrlist, 2)

    addr.append(random.randint(1, 200))

    frame_data2.append(addr)

frame_data2 = pandas.DataFrame(frame_data2, columns=['target', 'source', 'data'])

frame_data2.to_csv('frame_data2.csv', index=False)

print(frame_data2)

# 读取文件

file1 = pandas.read_csv('frame_data1.csv')

file2 = pandas.read_csv('frame_data2.csv')

程序代码2:该段代码实现了模拟网桥的功能。

import pandas

import numpy

# 网桥自学习 更新转发表的信息(添加转发表中没有的信息)

def updateForwardingTable(key, ForwardingTable=None):

    ForwardingTable.loc[ForwardingTable.shape[0]] = [key, port_dict[key]]  # 开辟转发表中的新的一行,然后存储新的地址和其对应的端口号

    print('更新后的转发表为')

    print(ForwardingTable)

# 通过广播进行查找发送

def broadcastSearch(line):

    for key in port_dict:  # 遍历所有的地址

        if key == line[0]:  # 地址匹配时

            print('广播发送成功\n')

            return

    print('没有找到目标地址,发送失败\n')

# 模拟网桥转发功能

def simulate_Bridge(line, ForwardingTable=None):  # line为帧中的数据,第一、二、三个数据分别为目的地址、源地址、数据

    print(f'网络接口{port_dict[line[1]]}收到数据帧')

    print(f'PC-{line[1]}向PC-{line[0]}发送数据{line[2]}')

    # 如果 源地址 不在转发表中, 则网桥需要将源地址记录在转发表中

    if line[1] not in numpy.array(ForwardingTable.address):

        print(f'转发表登记PC-{line[1]}源地址')

        updateForwardingTable(line[1], forwardingTable)

    # 如果 目的地址 不在转发表中, 则通过广播进行发送

    if line[0] not in numpy.array(ForwardingTable.address):

        print(f'PC-{line[0]}目的地址不在转发表中,通过广播进行发送')

        broadcastSearch(line)

        return

    # (源地址和目的地址均在转发表中时) 判断 源地址 和 目的地址 是否在同一个网段,即它们的端口号是否相等

    if numpy.array(ForwardingTable[ForwardingTable['address'] == line[1]]['port']) == numpy.array(

            ForwardingTable[ForwardingTable['address'] == line[0]]['port']):

        print('源地址和目的地址在同一个网络接口,丢弃该帧\n')

    else:

        num = numpy.array(ForwardingTable[ForwardingTable['address'] == line[0]]['port'])

        print(f'通过网络接口{num[0]}进行转发\n')

# 端口与地址的字典

port_dict = {'A': 1, 'B': 2, 'C': 2, 'D': 3, 'E': 2, 'F': 1, 'G': 1, 'H': 3, 'I': 2, 'J':2, 'K':2, 'L':3, 'M':1, 'N':1}

# 网桥生成的转发表

forwardingTable = pandas.DataFrame(columns=['address', 'port'])

# 读取初始化数据:帧文件的数据

frame_data1 = pandas.read_csv('frame_data1.csv')

frame_data2 = pandas.read_csv('frame_data2.csv')

print('第一个帧文件的数据为:')

print(frame_data1)

print('\n第二个帧文件的数据为:')

print(frame_data2)

# 从两个帧文件中交替读入帧数据

index1 = 0

index2 = 0

for i in range(max(len(frame_data1), len(frame_data2))):

    if index1 < len(frame_data1):

        # 获取文件1的一行数据,并转为列表:[targetAddr, sourceAddr, data]

        line1 = list(frame_data1.iloc[index1])  # 获取文件frame_data1中的第index1+1行数据

        print(f'网桥从网段中得到帧数据为{line1}')

        simulate_Bridge(line1, forwardingTable)

        index1 += 1

    if index2 < len(frame_data2):

        # 获取文件2的一行数据,并转为列表:[targetAddr, sourceAddr, data]

        line2 = list(frame_data2.iloc[index2])

        print(f'网桥从网段中得到帧数据为{line2}')

        simulate_Bridge(line2, forwardingTable)

        index2 += 1

# 读完所有的帧后,打印当前的转发表

print(f'所有文件中的帧数据处理完成后,此时的转发表内容为\n{forwardingTable}')

实验感想:
1、由于我平时比较少使用Python进行编程,用得比较多的是c语言和matlab。但是由于该实验需要进行文件的读写,C语言和MATLAB语言对于文件的读写都不是很方便;而且实验中预期还需要用到使用地址来匹配端口,要是使用C语言或者是MATLAB语言,需要用遍历才能完成匹配地址与端口进行匹配的操作,而Python中自带的字典恰恰非常适用且方便。

2、通过本次实验,我更加理解了一个知识点“网桥做简单的局域网连接,而路由器用于连接不同网络之间的数据传输”。

3、通过本实验的操作与编程,我对交换机自学习和转发帧的步骤更加熟悉,并能够用简化的步骤进行编程实现。

  1. 编写一个计算机程序用来计算一个文件的16位效验和。最快速的方法是用一个32位的整数来存放这个和。记住要处理进位(例如,超过16位的那些位),把它们加到效验和中。

要求:1)以命令行形式运行:check_sum  infile

      其中check_sum为程序名,infile为输入数据文件名。

2)输出:数据文件的效验和

附:效验和(checksum) 

    参见RFC1071 - Computing the Internet checksum

  • 原理:把要发送的数据看成16比特的二进制整数序列,并计算他们的和。若数据字节长度为奇数,则在数据尾部补一个字节的0以凑成偶数。
  • 例子:16位效验和计算,下图表明一个小的字符串的16位效验和的计算。

为了计算效验和,发送计算机把每对字符当成16位整数处理并计算效验和。如果效验和大于16位,那么把进位一起加到最后的效验和中。

计算机计算结果:

由此可知,若是直接将每个字符对应的十六进制数进行简单相加而不处理进位操作时,结果与正确的校验和结果不同。因此,需要需要将超过16位的那些数值加到低16位中去。

实现步骤:

1、先在设定好的路径下创建一个infile.txt的文件,文件中包含一个语句:Hello world.

2、编写check_sum程序,程序流程图如下所示:

程序流程图:

程序运行结果:

实验感想:

  1. 在pycharm终端中,需要注意路径是否正确。例如,我将该实验的程序文件check_sum和需要用到的文本文件infile都放置于目录  C:\Python_works\Python_learn\计算机网络  中。但是在pycharm终端中,默认的路径为  C:\Python_works  。所以,我在pycharm终端中输入指令:python check_sum.py后,一直提示未找到该文件名的文件。其实文件一直存在,只不过是路径没有匹配上。报错如下图所示:

解决办法,将文件 check_sum.py和infile.txt从目录  C:\Python_works\Python_learn\  转移至目录C:\Python_works。

  1. 实验过程中,我容易忘记自己定义的变量的数据类型,例如,我存储的十六进制数值列表就是使用str的。所以在进行一些操作时,使用+号表示的是两字符串的连接而非其十六进制数值形式的加法运算,这是容易出错的。

  1. 程序在处理进位的操作,我使用的方法是简单地将溢出的数值与十六进制最低位的数值进行相加,然后将相加结果转换为字符串1,然后再将十六进制非最低位的字符串1进行拼接,从而实现了处理进位,最终得到正确的校验和。

     

程序代码

import argparse

# 读取文件内容的函数

def readfile(path):

    with open(path, 'r', encoding='utf-8-sig') as f:

        content = f.read()

        f.close()

    return content

# 通过命令行参数解析器创建一个解析器对象

parser = argparse.ArgumentParser(description='Calculate checksum for a file')

# 添加一个命令行参数,表示文件路径,必须提供

parser.add_argument('--path', required=True, type=str)

# 使用解析器解析命令行参数

args = parser.parse_args()

# 从命令行参数中获取文件路径

file_path = args.path

# 读取文件内容

file_content = readfile(path=file_path)

print("文件内容为:", file_content)

# 将字符串转为十六进制  注意 这里的数据类型为 字符串类型

hex_data_list = [hex(ord(char)).replace('0x', '') for char in file_content]

# 对奇数长度字节的尾部补'00'

if 1 == len(hex_data_list) % 2:

    hex_data_list.append('00')

print("十六进制数据列表:", hex_data_list)

# 相邻两项进行合并

num_list = ['0x' + hex_data_list[i] + hex_data_list[i + 1] for i in range(0, len(hex_data_list), 2)]

print("合并后的十六进制数值列表:", num_list)

# 相加

check_sum = hex(sum([int(num, 16) for num in num_list]))  # 进行16进制的加法运算

check_sum = check_sum.replace('0x', '')  # 去掉多的一个前缀'0x'

print("未处理进位的相关问题时,结果为:", check_sum)  # 打印结果为:271fa

# 处理进位

if len(check_sum) > 4:

    check_sum_part1 = '0x' + check_sum[:len(check_sum) - 4]  # 提取高位(高的第一位)

    print("提取高位:", check_sum_part1)

    check_sum_part2 = '0x' + check_sum[len(check_sum_part1) - 4:]  # 提取低位(低的第一位)

    print("提取低位:", check_sum_part2)

    temp1 = hex(int(check_sum_part1, 16) + int(check_sum_part2, 16))  # 将高位和低位进行十六进制加法操作

    print("高位和低位相加:", check_sum_part1, "+", check_sum_part2, "=", temp1)

    temp1 = temp1.replace('0x', '')

    index1 = len(check_sum_part1) - 2

    index2 = len(check_sum) - (abs(len(check_sum_part2)) - 2)

    temp2 = check_sum[index1:index2]

    temp2 = '0x' + temp2

    check_sum = temp2 + temp1

    print("将高位和低位相加后的结果赋值到十六进制末尾:", check_sum)

print("数据文件的校验和为:", check_sum)

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

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

相关文章

C++ 协程 学习笔记

协程的优势就是比线程切换的时间少很多&#xff0c;协程的切换时间是纳秒&#xff0c;而进行切换的时间是微秒 单线程用协程可以轻松的处理并发任务 co_yield和co_await可以将协程暂停下来 resume又把协程激活 如果c函数里有co_await、co_return、co_yield就会自动判定为协程…

可搜索加密:保护隐私的搜索技术

在信息化、数字化快速发展的今天&#xff0c;数据的安全性和隐私性已成为公众关注的焦点。随着云计算、大数据等技术的广泛应用&#xff0c;数据共享与协同工作日益普遍&#xff0c;但如何在确保数据安全性的前提下&#xff0c;实现数据的快速、高效检索&#xff0c;成为了一个…

一个Level 0富文本编辑器的进化历程

本文作者为 360 奇舞团前端开发工程师 一个Level 0富文本编辑器的进化历程 富文本编辑器是我们在生活中常用到的编辑工具&#xff0c;本文将为大家介绍富文本编辑器技术成长的历程&#xff0c;在最后会带大家利用document.execCommand实现一个简单的传统编辑器。 ps&#xff1a…

EasyCVR视频汇聚平台无法自动播放视频的原因排查与解决

国标GB28181协议EasyCVR安防视频监控平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流…

contenteditable可编辑功能,监听输入内容与回车操作

contenteditable 在div元素上添加contenteditable"true" 可以让div变成可编辑元素 <div class"word-block" contenteditable"true"></div>同时还支持回车换行 回车后就会生成一个div元素 添加 -webkit-user-modify: read-write-p…

spring DisposableBean作用,在spring Bean销毁时的钩子 以及@PreDestroy

DisposableBean 作用 在Spring框架中&#xff0c;DisposableBean是一个接口&#xff0c;它定义了一个单一的方法&#xff0c;用于在Spring容器关闭时或一个由Spring管理的Bean不再需要时执行特定的清理操作。当一个Bean实现了DisposableBean接口&#xff0c;Spring容器会在销毁…

VTC视频时序控制器原理以及Verilog实现

文章目录 一、前言二、视频时序控制原理三、Verilog实现3.1 代码3.2 仿真以及分析 一、前言 VTC&#xff08;Video Timing Controller&#xff09;是一种用于产生视频时序的控制器&#xff0c;在图像领域经常会输出各种分辨率和帧率的视频格式。因此为了方便&#xff0c;设置一…

C++: IO流

目录 1、C语言输入输出 流的概念&#xff1a; 2、CIO流 3、C文件IO流 1、C语言输入输出 C语言中我们用到的最频繁的输入输出方式就是scanf () 与 printf() 。 scanf(): 从标准输入设备 ( 键 盘 ) 读取数据&#xff0c;并将值存放在变量中 。 printf(): 将指定的文…

C语言入门课程学习笔记2

C语言入门课程学习笔记2 第8课 - 四则运算与关系运算第9课 - 逻辑运算与位运算第10课 - 深度剖析位运算第11课 - 程序中的选择结构 本文学习自狄泰软件学院 唐佐林老师的 C语言入门课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 第8课 - 四则运算与关系…

pycharm安装AI写代码插件

在IDE安装特慢&#xff08;可能找不到插件&#xff09; 去官网搜一下 对应安装包 下载zip在IDE解压 插件--已安装齿轮图标--从磁盘里安装 选择下载的插件 应用 --重启OK

在ubuntu上安装mysql(在线安装需要)

安装环境 虚拟机系统&#xff1a; Ubuntu 打开虚拟机 安装步骤 (1) 安装 将系统中的所有软件包都升为最新版本 sudo apt update 安装 MySQL sudo apt install mysql-server查询 MySQL 版本 mysql --version(2) MySQL 安全设置 进入 MySQL Shell sudo mysql设置 …

window平台C#实现软件升级功能(控制台)

window平台C#实现软件升级功能 之前用window窗体实现过一个升级功能&#xff0c;后来发现多个项目都需要升级功能&#xff0c;现改成可接收参数实现一种通用的exe.改用控制台方式实现这个升级功能&#xff0c;这样不仅实现了接收参数&#xff0c;升级程序体积也比原来的窗体形式…

java自动生成pojo,springboot自动生成pojo

第一步 pom引入依赖 <dependencies><!-- mybatis-generator --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.7</version></dependency>&…

开源电商小程序源码+搭建 支持全平台端口+商家自营+多商户入驻 带分销功能 可自用DIY界面

开源电商小程序源码系统为商家提供了一个快速搭建和部署电商平台的解决方案。商家可以利用该系统&#xff0c;在较短的时间内构建出功能齐全、界面美观的电商小程序&#xff0c;无需从零开始编写代码&#xff0c;从而大大节省了开发成本和时间。 分享一个开源电商小程序源码系…

OpenUI在windows下部署使用

OpenUI OpenUI是一个基于Python的AI对话平台&#xff0c;支持接入多种AI模型。 通过聊天的方式来进行UI设计&#xff0c;你可以通过文字来描述你想要的UI界面&#xff0c;OpenUI可以帮你实时进行渲染出效果 安装OpenUI 这里预设你的电脑上已安装git、Python和pip&#xff0…

Nginx 搭建Web服务

题目&#xff1a; 1.web服务器的主机ip&#xff1a;192.168.78.128 2.web服务器的默认访问目录为/var/www/html 默认发布内容为default‘s page 3.站点news.timinglee.org默认发布目录 为/var/www/virtual/timinglee.org/news 默认发布内容为 news.timinglee.org 4.站点login.t…

Power BI 如何解决月份排序错误/乱序问题(自定义顺序/正确排序)

问题描述 在创建图标时&#xff0c;月份标签没有按照正确的顺序排列。 解决方案&#xff1a; Sort by Column 单击选中排序错误的列&#xff08;MMM&#xff09;根据列排序 (sort by Column)选择需要根据哪一列排序。 这里选择的是Month列&#xff0c;这一列有月份的序号1-…

如何通过香港站群服务器提升跨境电商交易效率?

如何通过香港站群服务器提升跨境电商交易效率? 在全球电子商务迅速发展的今天&#xff0c;跨境电商已成为企业拓展国际市场、获取更多商机的重要途径。然而&#xff0c;跨境电商面临的挑战也不容小觑&#xff0c;尤其是在交易效率方面。利用香港站群服务器&#xff0c;不仅可…

做抖音小店如何选品?这几个技巧,精准“锁定”爆品!

哈喽~我是电商月月 做抖音小店最重要的就是选品&#xff0c;这点大家都知道 一个店铺商品选的好&#xff0c;顾客喜欢&#xff0c;质量完好&#xff0c;销量和售后都不用操心&#xff0c;和达人合作时&#xff0c;爆单的机会也就越高 那这种商品是什么样的&#xff0c;新手开…

快速了解-BTP

名词了解 BTP&#xff1a;SAP Business Technology Platform 是一个技术和业务的平台ETWEAVER &#xff08;SAP NW&#xff09;&#xff1a;NetWeaver本质上是SAP一系列技术产品的集成平台PAAS Cloud Foundry&#xff08;云原生&#xff09;&#xff1a;开源云服务平台烟囱式…