计算机网络实验(一)

计算机网络实验目录

  • eth协议实现
  • ARP协议实现
  • RIP路由配置和协议分析
  • IP协议实现
  • ICMP协议实现
  • UDP协议实现
  • NAT组网
  • 邮件客户端的设计与实现

文章目录

  • 计算机网络实验目录
  • 前言
  • 基础知识
      • 一、数据链路层基本工作
      • 二、数据链路层协议
      • 二、MAC地址
      • 三、以太网MAC帧格式
  • 实验实现
    • 一、分析
    • 字节序分析
    • 二、代码:


前言

HITSZ 2022春计算机网络实验记录,并结合计网理论课程内容进行复习总结
实验网址


基础知识

一、数据链路层基本工作

数据链路层的基本工作:

  • 封装成帧:添加首部(SOH)和尾部(EOT)进行帧界定,划分IP数据报内容,首部和尾部还包含必要的控制信息。各种链路层协议都对首部和尾部有明确的规定,同时规定数据部分的长度上限(MTU)
  • 透明传输:在数据部分中可能出现的SOH和EOT前加ESC转义字符
  • 差错检测:如循环冗余检测CRC(FCS帧检验序列,属于数据后面添加的冗余码

二、数据链路层协议

  • PPP协议(点对点协议,可靠传输协议):用户计算机与ISP进行通信时所用的协议
  • 广播信道(一对多通信):以太网使用
    • CSMA/CD协议:不可靠传输协议,使用载波监听和碰撞检测,是总线型以太网采用的协议。

二、MAC地址

MAC地址实际上是局域网适配器的标识地址,又叫物理地址或者硬件地址,MAC的6字节地址被固化在适配器的ROM中。世界上的每一个适配器都有唯一的地址。

三、以太网MAC帧格式

总线型和星型网络结构均使用以太网帧

  • 以太网帧不需要EOT:使用曼彻斯特编码,但接受的电平不发生转变时,只需前移4个字节即可找到数据的结束位置
    计算机网络实验(一)_第1张图片

去除报头和FCS得到链路层的数据帧:

  • MAC目标地址:接收帧的网络适配器的物理地址(MAC地址),6个字节。
    • 当网卡接收到一个数据帧时,首先会检查该帧的目的地址,如果与当前适配器的物理地址相同,进一步处理
    • 帧的目的地址为广播地址(FF-FF-FF-FF-FF-FF),进一步处理;
    • 否,则直接丢弃。
  • MAC源地址:发送帧的网络适配器的物理地址,6个字节。
  • 类型,2个字节:
    • 当该值在0x05DC(10进制数为1500)以下,表示该以太网数据帧长度;
    • 在0x0600以上时,则表示上层协议的类型,标识数据交付哪个协议处理。
      计算机网络实验(一)_第2张图片

实验实现

一、分析

实际上就是对接收到的以太网MAC帧进行处理,由于封装好了很多包,所以只需要进行基础函数编写,需要注意:

  • memcpy使用的时候最好指定清楚拷贝的大小
  • 注意大小端字节序

字节序分析

原文链接
网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节。小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双方都正确的收发了数据。而相同平台进行通信时,如果双方都进行转换最后虽然能够正确收发数据,但是所做的转换是没有意义的,造成资源的浪费。而不同平台进行通信时必须进行转换,不转换会造成错误的收发数据,字节序转换函数会根据当前平台的存储模式做出相应正确的转换,如果当前平台是大端,则直接返回不进行转换,如果当前平台是小端,会将接收到得网络字节序进行转换。
计算机网络实验(一)_第3张图片

二、代码:

void ethernet_in(buf_t *buf)
{
    // TO-DO
    //首先判断数据长度,如果数据长度小于以太网头部长度,则认为数据包不完整,丢弃不处理。
    if(buf->len < sizeof(ether_hdr_t))
    {
        return;
    }
    //调用buf_remove_header()函数移除加以太网包头。
    ether_hdr_t header;
    memcpy(&header, buf->data, sizeof(ether_hdr_t));
    buf_remove_header(buf, sizeof(ether_hdr_t));
    //调用net_in()函数向上层传递数据包, protocol需要反转大小端,其它不要(源地址和目的地址反转后也是唯一)
    net_in(buf, swap16(header.protocol16), header.src);
}
/**
 * @brief 处理一个要发送的数据包
 * 
 * @param buf 要处理的数据包
 * @param mac 目标MAC地址
 * @param protocol 上层协议
 */
void ethernet_out(buf_t *buf, const uint8_t *mac, net_protocol_t protocol)
{
    // TO-DO
    //Step1 :首先判断数据长度,如果不足46则显式填充0,填充可以调用buf_add_padding()函数来实现。
    if(buf->len < 46)
    {
        buf_add_padding(buf, (size_t)(46 - buf->len));
    }
    //Step2 :调用buf_add_header()函数添加以太网包头。
    buf_add_header(buf, sizeof(ether_hdr_t));
    ether_hdr_t *hdr = (ether_hdr_t *)buf->data;
    //Step3 :填写目的MAC地址。
    memcpy(hdr->dst, mac, NET_MAC_LEN * sizeof(uint8_t)); 
    //Step4 :填写源MAC地址,即本机的MAC地址。
    memcpy(hdr->src, net_if_mac, NET_MAC_LEN * sizeof(uint8_t));
    //Step5 :填写协议类型 protocol。需要反转
    uint16_t protocol16 = swap16(protocol);
    memcpy(&(hdr->protocol16),  &protocol16, sizeof(uint16_t));
    //Step6 :调用驱动层封装好的driver_send()发送函数,将添加了以太网包头的数据帧发送到驱动层。
    driver_send(buf);
}

你可能感兴趣的:(计算机网络,网络协议)