【斯坦福CS144】Lab4

一、实验目的

完成一个网络接口实现。

二、实验内容

完成一个网络接口实现,其大部分工作是:为每个下一跳IP地址查找(和缓存)以太网地址。而这种协议被称为地址解析协议ARP。

三、实验过程

在minnow目录下输入git merge origin/check4-startercode获取Lab4

用文本编辑器打开./src/network_interface.hh

修改代码

用文本编辑器打开./src/network_interface.cc

修改代码

在build目录下输入make进行编译

输入make check4进行测试

测试成功,实验结束。

四、实验体会

1.在实现整个网络接口时,必须确保几点:

①ARP条目 TTL 为30s,时间到期后需要将其从 ARP Table 中删除。

若发送 IP 报文时,发现 ARP Table 中无目标 MAC 地址,则立即发送 ARP 请求报文,同时将当前 IP 报文暂时缓存,直至获取到目标 MAC 地址后再重新发送。

②不同目标 IP 的 ARP 请求报文之间的发送间隔,不能超过 5s。

③如果 ARP 请求报文在 5 秒内仍然无响应,则重新发送。

④当网络接口接收到一个以太网帧时,

必须丢弃目的 MAC 地址不为当前网络接口 MAC 地址

除了 ARP 协议需要比较自己的 IP 地址以外,不要在其他任何地方进行 IP 比较,因为网络接口位于链路层。

如果是发给自己的 ARP 请求,那么要忽略掉发送来的 ARPMessage::target_ethernet_address,因为发送者自己也不知道这个要填写什么,该字段无意义。

无论接收到的是 ARP 请求包或者 ARP 响应包,只要是明确发给自己的,那么这里面的 src_ip_addr 和 src_eth_addr 都可用于更新当前的 ARP 表。

2.如何理解NetworkInterface:

①一个将IP(互联网层或网络层)与以太网(网络访问层或链路层)连接的"网络接口",该模块是TCP/IP协议栈的最底层(连接IP与更底层的网络协议,如以太网),但同样的模块也作为路由器的一部分反复使用;

②路由器通常有许多网络接口,其工作是在不同的接口之间路由互联网数据报,网络接口将来自"客户端"(例如TCP/IP协议栈或路由器)的数据报转换为以太网帧。为了填写以太网的目标地址,它查找每个数据报的下一个IP跳的以太网地址,并使用地址解析协议ARP进行请求。在相反的方向,网络接口接受以太网帧,检查它们是否是针对它的,如果是,则根据其类型处理有效载荷。

如果是IPv4数据报,网络接口将其向上传递到协议栈。

如果是ARP请求或回复,网络接口将处理该帧,并根据需要进行学习或回复。

五、代码附录

network_interface.hh

#pragma once#include "address.hh"
#include "ethernet_frame.hh"
#include "ipv4_datagram.hh"#include <iostream>
#include <list>
#include <optional>
#include <queue>
#include <unordered_map>
#include <utility>// A "network interface" that connects IP (the internet layer, or network layer)
// with Ethernet (the network access layer, or link layer).// This module is the lowest layer of a TCP/IP stack
// (connecting IP with the lower-layer network protocol,
// e.g. Ethernet). But the same module is also used repeatedly
// as part of a router: a router generally has many network
// interfaces, and the router's job is to route Internet datagrams
// between the different interfaces.// The network interface translates datagrams (coming from the
// "customer," e.g. a TCP/IP stack or router) into Ethernet
// frames. To fill in the Ethernet destination address, it looks up
// the Ethernet address of the next IP hop of each datagram, making
// requests with the [Address Resolution Protocol](\ref rfc::rfc826).
// In the opposite direction, the network interface accepts Ethernet
// frames, checks if they are intended for it, and if so, processes
// the the payload depending on its type. If it's an IPv4 datagram,
// the network interface passes it up the stack. If it's an ARP
// request or reply, the network interface processes the frame
// and learns or replies as necessary.
class NetworkInterface
{
private:// Ethernet (known as hardware, network-access, or link-layer) address of the interfaceEthernetAddress ethernet_address_;// IP (known as Internet-layer or network-layer) address of the interfaceAddress ip_address_;std::queue<EthernetFrame> send_frame_{};std::unordered_map<uint32_t, std::queue<InternetDatagram>> store_dgram_{};//std::queue<std::pair<InternetDatagram, Address>> store_dgram_{};//这里key值不能选Address,它没有拷贝构造函数,=重载std::unordered_map<uint32_t, std::pair<EthernetAddress, size_t>> map_ip2mac_{};std::unordered_map<uint32_t,size_t> map_arp_time_{};public:// Construct a network interface with given Ethernet (network-access-layer) and IP (internet-layer)// addressesNetworkInterface( const EthernetAddress& ethernet_address, const Address& ip_address );// Access queue of Ethernet frames awaiting transmissionstd::optional<EthernetFrame> maybe_send();// Sends an IPv4 datagram, encapsulated in an Ethernet frame (if it knows the Ethernet destination// address). Will need to use [ARP](\ref rfc::rfc826) to look up the Ethernet destination address// for the next hop.// ("Sending" is accomplished by making sure maybe_send() will release the frame when next called,// but please consider the frame sent as soon as it is generated.)void send_datagram( const InternetDatagram& dgram, const Address& next_hop );// Receives an Ethernet frame and responds appropriately.// If type is IPv4, returns the datagram.// If type is ARP request, learn a mapping from the "sender" fields, and send an ARP reply.// If type is ARP reply, learn a mapping from the "sender" fields.std::optional<InternetDatagram> recv_frame( const EthernetFrame& frame );// Called periodically when time elapsesvoid tick( size_t ms_since_last_tick );
};

network_interface.cc

#include "network_interface.hh"#include "arp_message.hh"
#include "ethernet_frame.hh"using namespace std;// ethernet_address: Ethernet (what ARP calls "hardware") address of the interface
// ip_address: IP (what ARP calls "protocol") address of the interface
NetworkInterface::NetworkInterface( const EthernetAddress& ethernet_address, const Address& ip_address ): ethernet_address_( ethernet_address ), ip_address_( ip_address )
{cerr << "DEBUG: Network interface has Ethernet address " << to_string( ethernet_address_ ) << " and IP address "<< ip_address.ip() << "\n";
}// dgram: the IPv4 datagram to be sent
// next_hop: the IP address of the interface to send it to (typically a router or default gateway, but
// may also be another host if directly connected to the same network as the destination)// Note: the Address type can be converted to a uint32_t (raw 32-bit IP address) by using the
// Address::ipv4_numeric() method.
void NetworkInterface::send_datagram( const InternetDatagram& dgram, const Address& next_hop )
{//以太网帧可以携带Internetdatagram,也可以携带arpmessage//(void)dgram;//(void)next_hop;uint32_t target_ip = next_hop.ipv4_numeric();//uint32_t source_address = dgram.header.src;//uint32_t destination_address = dgram.header.dst;//发送到next_hop, 而不是dgram的dstauto it = map_ip2mac_.find(target_ip);//nexthop的以太网地址已知,封装dgram发送if(it!=map_ip2mac_.end()){EthernetFrame send_frame{{it->second.first, ethernet_address_, EthernetHeader::TYPE_IPv4},serialize(dgram)};//send_frame.header.dst = it->second.first;send_frame_.push(send_frame);return;}//nexthop的以太网地址未知,如果没发过arp就发request arp,把dgram缓存起来if(map_arp_time_.find(target_ip)==map_arp_time_.end()){ARPMessage arp_send;arp_send.opcode = ARPMessage::OPCODE_REQUEST;arp_send.sender_ethernet_address = ethernet_address_;arp_send.sender_ip_address = ip_address_.ipv4_numeric();arp_send.target_ip_address = target_ip;EthernetFrame send_frame{{ETHERNET_BROADCAST, ethernet_address_, EthernetHeader::TYPE_ARP}, serialize(arp_send)};send_frame_.push(send_frame);map_arp_time_.insert(make_pair(target_ip, 0));//发完arp之后加入到map里面记录下来}//缓存dgramauto it_store_dgram = store_dgram_.find(target_ip);if(it_store_dgram == store_dgram_.end()){std::queue<InternetDatagram> q_dgram;store_dgram_.insert(make_pair(target_ip, q_dgram));//store_dgram_[target_ip].push(dgram);}store_dgram_[target_ip].push(dgram);return;
}// frame: the incoming Ethernet frame
optional<InternetDatagram> NetworkInterface::recv_frame( const EthernetFrame& frame )
{if(frame.header.dst!=ethernet_address_ && frame.header.dst!=ETHERNET_BROADCAST)return{};//有点疑惑为什么会出现这种发错的情况,但是测试样例里面有一个这样的例子//(void)frame;//收到arp,两种情况,收到的是request或者replyif(frame.header.type==EthernetHeader::TYPE_ARP){ARPMessage rec_arp;parse(rec_arp, frame.payload);map_ip2mac_.insert(make_pair(rec_arp.sender_ip_address, make_pair(rec_arp.sender_ethernet_address, 0)));//收到的是request,如果request的是自己的以太网地址,就发送一个reply的arpmessage,发送给request方if(rec_arp.opcode==ARPMessage::OPCODE_REQUEST){if(rec_arp.target_ip_address == ip_address_.ipv4_numeric()){ARPMessage arp_reply;arp_reply.opcode = ARPMessage::OPCODE_REPLY;arp_reply.sender_ethernet_address = ethernet_address_;arp_reply.sender_ip_address = ip_address_.ipv4_numeric();arp_reply.target_ethernet_address = rec_arp.sender_ethernet_address;arp_reply.target_ip_address = rec_arp.sender_ip_address;EthernetFrame reply_frame{{rec_arp.sender_ethernet_address, ethernet_address_, EthernetHeader::TYPE_ARP},serialize(arp_reply)};send_frame_.push(reply_frame);return{};}else return{};}//收到arp之后,无论arp是reply还是request都检查一下有没有可以发送的dgramauto it = store_dgram_.find(rec_arp.sender_ip_address);if(it!=store_dgram_.end()){while(it->second.empty()==false){InternetDatagram dgram = it->second.front();it->second.pop();EthernetFrame send_frame{{rec_arp.sender_ethernet_address, ethernet_address_,EthernetHeader::TYPE_IPv4},serialize(dgram)};send_frame_.push(send_frame);}if(it->second.empty()) store_dgram_.erase(it);}}//frame携带的是internetdatagramelse if(frame.header.type==EthernetHeader::TYPE_IPv4){InternetDatagram dgram;parse(dgram, frame.payload);return dgram;}return {};
}// ms_since_last_tick: the number of milliseconds since the last call to this method
void NetworkInterface::tick( const size_t ms_since_last_tick )
{for(auto it = map_ip2mac_.begin();it!=map_ip2mac_.end();){it->second.second += ms_since_last_tick;if(it->second.second >= 30000)it=map_ip2mac_.erase(it);else it++;}for(auto it = map_arp_time_.begin(); it!=map_arp_time_.end();){it->second += ms_since_last_tick;if(it->second>=5000) it=map_arp_time_.erase(it);else it++;}//for(auto it = map)//(void)ms_since_last_tick;
}optional<EthernetFrame> NetworkInterface::maybe_send()
{if(!send_frame_.empty()){auto frame = send_frame_.front();send_frame_.pop();return {frame};}else return{};
}

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

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

相关文章

DAMA数据管理知识体系(第15章 数据管理成熟度评估)

课本内容 15.1 引言 概要 能力成熟度评估&#xff08;Capability Maturity Assessment&#xff0c;CMA&#xff09;是一种基于能力成熟度模型&#xff08;Capability Maturity Model&#xff0c;CMM&#xff09;框架的能力提升方案&#xff0c;描述了数据管理能力初始状态发展到…

简易登录注册;测试类;postman测试;

项目是如何创建的&#xff0c;最简易的登陆注册功能是怎么实现的&#xff0c;数据库不能明文存放密码&#xff0c;密码经过了怎么样的处理存入数据库 前端使用nodejs18 后端项目需要等待maven加载完相关依赖&#xff0c;后端使用java17 1后端 1.1 创建项目所需要的数据库 内…

Sentinel最全笔记,详细使用步骤教程清单

一、Sentinel的基本功能 1、流量控制 流量控制在网络传输中是一个常用的概念&#xff0c;它用于调整网络包的发送数据。然而&#xff0c;从系统稳定性角度考虑&#xff0c;在处理请求的速度上&#xff0c;也有非常多的讲究。任意时间到来的请求往往是随机不可控的&#xff0c;…

Unity转Unreal5之从入门到精通 Spline(样条曲线)组件的使用

前言 Spline 组件 能编辑 样条曲线,定义一条路径,路径上的点可以通过距离起点的长度获取,因此可以实现 物体沿路径连续移动 的效果或者 物体沿路径分布 的效果。 今天我们就来实现一个简单的Spline样条曲线的Demo 实现一个沿路径运动的功能 1.新建一个基于 Actor 的蓝图…

ICE/TURN/STUN/Coturn服务器搭建

ICE 当我们想要实现在公网环境下的语音/视频通话功能时&#xff0c;就需要用到ICE交互式连接建立。ICE不是一种协议&#xff0c;整合了 STUN 和 TURN 两种协议&#xff08;用于 NAT 穿透&#xff09;的框架。 ICE的主要目标是解决NAT&#xff08;网络地址转换&#xff09;穿越…

[ C++ ] C++ 类和对象 -- 类的六个默认成员函数

目录 1.构造函数 2.析构函数 3.拷贝构造函数 4.赋值操作符重载 5.两个取地址操作符的重载 在C中当你创建一个空类&#xff0c;那这个空类是什么都没有吗&#xff1f;不是的&#xff0c;编译器会默认帮你生成六个成员函数 1.构造函数 构造函数是特殊的成员函数&#xff0c;…

leetcode 10.9 94.二叉树的中序遍历

94. 二叉树的中序遍历 已解答 简单 相关标签 相关企业 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a…

makefile的基本练习

假设有如下目录结构&#xff1a;&#xff08;目录结构图&#xff09; 完成以下操作&#xff1a; 1、通过纯命令编写Makefile文件&#xff0c;并发现使用纯命令的不足&#xff1b; 2、在Makefile中&#xff0c;添加变量&#xff0c;简化参数的重复书写&#xff1b; 3、尝试在多目…

『网络游戏』客户端使用PESorket发送消息到服务器【14】

上一章服务器已经完成使用PESorket 现在我们将其导出在客户端中使用 生成成功后复制 粘贴到Unity项目中 进入Assets文件夹 粘贴两个.dll 创建脚本:ClientSession.cs 编写脚本: ClientSession.cs 编写脚本:GameStart.cs 将GameStart.cs脚本绑定在摄像机上 运行服务器 运行客户端…

Linux网络驱动实验

直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81 本文仅作为个人笔记使用&#xff0c;方便进一步记录自己的实践总结。 网络驱动是 linux 里面驱动三巨头之一&#xff0c;linux 下的网络功能非常强大&#xff0c;嵌入式 linux 中也常常用到网络功能。前面我们已经讲过…

8.12 矢量图层面要素单一符号使用十三(插值线渲染边界)

8.12 矢量图层面要素单一符号使用十三(插值线渲染边界)-CSDN博客 目录 前言 插值线渲染边界&#xff08;Outline: Interpolated Line&#xff09; QGis设置面符号为插值线渲染边界&#xff08;Outline: Interpolated Line&#xff09; 二次开发代码实现插值线渲染边界&…

Base64字符串转图片在线工具

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 基本原理 Base64编码&#xff0c;作为一种将二进制数据转换为文本格式的方法&#xff0c;其核心在于利用64个可打印字符来表征任意的二进制信息。这一编码方式的出现&#…

erlang学习:Linux命令学习11

crontab命令 crontab命令是用于管理定时任务的命令行工具。它提供了多种选项和参数&#xff0c;可以用来创建、编辑、查看和删除用户的定时任务。 常用命令 以下是一些常用的crontab命令&#xff1a; crontab -e&#xff1a;编辑当前用户的定时任务列表。该命令会在默认编辑…

PostgreSQL学习笔记三:数据类型和运算符

数据类型和运算符 PostgreSQL 支持多种数据类型和运算符&#xff0c;以下是一些常见的数据类型和运算符的概述&#xff1a; 数据类型 基本数据类型 整数类型&#xff1a; SMALLINT&#xff1a;2 字节&#xff0c;范围 -32,768 到 32,767。INTEGER&#xff1a;4 字节&#xff0…

minio简单使用

文章目录 简介官方地址Linux下载安装安装服务启动关闭帮助命令 java开发minio依赖包新建项目pom配置文件配置类Service测试类运行测试 Api使用前言针对桶的操作查看某个桶是否存在创建一个桶返回桶列表删除一个桶 针对文件的操作上传文件到桶中(本地文件上传)上传文件到桶中(基…

C++标准模板库STL之容器--string

STL简介 STL&#xff08;standard template libaray - 标准模板库&#xff09;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;还是一个包罗了数据结构与算法的软件框架。 STL的六大组件及相关函数 仿函数greater、less……算法find、swap、reverse、…

2020年华为杯数学建模竞赛D题论文和代码

无人机集群协同对抗 摘 要&#xff1a; 本文针对非线性约束条件下红蓝双方无人机集群协同对抗的最优规划问题&#xff0c;结合贪婪队形、非线性规划、内点法、蒙特卡洛方法和全联立正交配置有限元法&#xff0c;构建了无人机集群协同对抗推演模型。 针对问题一&#…

OBOO鸥柏全户外液晶广告机室外触控一体机技术标参数公布

整机参数技术公布&#xff1a; OBOO鸥柏智能43寸/49寸/55寸/65寸/75寸/86寸/98寸/110寸全户外LCD液晶安卓系统网络广告屏/室外触摸屏查询一体机投标参数投标标准款。 1、液晶屏具工业级液晶面板&#xff0c;亮度为2000cd/㎡&#xff0c;并且具备自动感光亮度调节&#xff0c;…

工业网关的主要功能-天拓四方

引言&#xff1a; 在当今工业自动化的浪潮中&#xff0c;工业网关作为一种重要的网络连接设备&#xff0c;扮演着不可或缺的角色。其强大的功能使得工业设备能够无缝接入网络&#xff0c;实现远程监控、控制、数据采集和协议转换等&#xff0c;极大地提升了工业生产的效率和智…

算法专题五: 位运算

目录 常见位运算总结1. 位1的个数2. 比特位计数3. 汉明距离4. 只出现一次的数字5. 只出现一次的数字Ⅲ6. 判定字符是否唯一7. 丢失的数字8. 两正数之和9. 只出现一次的数字Ⅲ10. 消失的两个数字 常见位运算总结 重点 : 1. 位1的个数 算法思路: 这道题就用到了我们总结的那个第…